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:
-rw-r--r--CMakeLists.txt11
-rw-r--r--SConstruct6
-rwxr-xr-xbuild_files/build_environment/install_deps.sh5
-rw-r--r--build_files/cmake/macros.cmake5
-rw-r--r--doc/build_systems/cmake.txt82
-rw-r--r--doc/python_api/rst/bge.logic.rst2
-rwxr-xr-xextern/carve/bundle.sh2
-rw-r--r--extern/carve/files.txt174
-rw-r--r--extern/carve/include/carve/csg_triangulator.hpp2
-rw-r--r--extern/carve/include/carve/geom3d.hpp19
-rw-r--r--extern/carve/include/carve/geom_impl.hpp2
-rw-r--r--extern/carve/include/carve/input.hpp81
-rw-r--r--extern/carve/include/carve/mesh.hpp38
-rw-r--r--extern/carve/include/carve/mesh_impl.hpp59
-rw-r--r--extern/carve/lib/intersect.cpp4
-rw-r--r--extern/carve/lib/intersect_face_division.cpp3
-rw-r--r--extern/carve/lib/mesh.cpp36
-rw-r--r--extern/carve/lib/polyhedron.cpp2
-rw-r--r--extern/carve/patches/series1
-rw-r--r--extern/carve/patches/strict_flags.patch22
-rw-r--r--extern/libmv/CMakeLists.txt18
-rw-r--r--extern/libmv/ChangeLog430
-rw-r--r--extern/libmv/SConscript6
-rwxr-xr-xextern/libmv/bundle.sh7
-rw-r--r--extern/libmv/files.txt22
-rw-r--r--extern/libmv/libmv-capi.cpp466
-rw-r--r--extern/libmv/libmv-capi.h89
-rw-r--r--extern/libmv/libmv/multiview/euclidean_resection.cc4
-rw-r--r--extern/libmv/libmv/multiview/fundamental.cc4
-rw-r--r--extern/libmv/libmv/multiview/homography.cc15
-rw-r--r--extern/libmv/libmv/multiview/homography.h8
-rw-r--r--extern/libmv/libmv/multiview/panography.h181
-rw-r--r--extern/libmv/libmv/simple_pipeline/bundle.cc453
-rw-r--r--extern/libmv/libmv/simple_pipeline/bundle.h12
-rw-r--r--extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc24
-rw-r--r--extern/libmv/libmv/simple_pipeline/camera_intrinsics.h31
-rw-r--r--extern/libmv/libmv/simple_pipeline/intersect.cc80
-rw-r--r--extern/libmv/libmv/simple_pipeline/modal_solver.cc180
-rw-r--r--extern/libmv/libmv/simple_pipeline/pipeline.cc2
-rw-r--r--extern/libmv/libmv/simple_pipeline/rigid_registration.cc182
-rw-r--r--extern/libmv/libmv/simple_pipeline/rigid_registration.h68
-rw-r--r--extern/libmv/patches/series1
-rw-r--r--extern/libmv/patches/v3d_verbosity.patch12
-rw-r--r--extern/libmv/third_party/ceres/CMakeLists.txt40
-rw-r--r--extern/libmv/third_party/ceres/ChangeLog730
-rw-r--r--extern/libmv/third_party/ceres/SConscript4
-rwxr-xr-xextern/libmv/third_party/ceres/bundle.sh16
-rw-r--r--extern/libmv/third_party/ceres/files.txt33
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h71
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/ceres.h8
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/cost_function_to_functor.h752
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/crs_matrix.h32
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h215
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/fpclassify.h2
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/gradient_checker.h222
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h158
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h6
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/macros.h12
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h29
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/numeric_diff.h199
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h15
-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.h43
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/numeric_diff_cost_function.h374
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/numeric_diff_functor.h346
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/ordered_groups.h176
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/problem.h156
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/rotation.h196
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/sized_cost_function.h30
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/solver.h313
-rw-r--r--extern/libmv/third_party/ceres/include/ceres/types.h110
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/array_utils.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc20
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h29
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h6
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc34
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h15
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/collections_port.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc3
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h9
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc236
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h88
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/corrector.cc17
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc10
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/cxsparse.h5
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_jacobian_writer.h11
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc13
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc29
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc16
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h1
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc18
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h4
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/evaluator.h17
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/execution_summary.h90
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/file.cc3
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc4
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/graph.h25
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h4
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc64
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h12
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h5
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search.cc211
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search.h212
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search_direction.cc145
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search_direction.h (renamed from extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.h)55
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.cc283
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.h77
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc72
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/linear_solver.h56
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc109
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h99
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/map_util.h1
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/minimizer.cc67
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/minimizer.h24
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/mutex.h6
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/parameter_block.h61
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.cc (renamed from extern/libmv/third_party/ceres/internal/ceres/schur_ordering.cc)29
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.h (renamed from extern/libmv/third_party/ceres/internal/ceres/schur_ordering.h)16
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/polynomial.cc (renamed from extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.cc)141
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/polynomial.h134
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/preconditioner.cc63
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/preconditioner.h148
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/problem.cc64
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc567
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/problem_impl.h62
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h28
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/residual_block.cc6
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/residual_block.h21
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc4
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc49
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h6
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc145
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h110
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/solver.cc331
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc1029
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/solver_impl.h95
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc36
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/split.cc3
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/split.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/stl_util.h16
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc3
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/stringprintf.h6
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc7
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/suitesparse.h4
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc3
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc238
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h12
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc32
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/types.cc208
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/visibility.cc3
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/visibility.h2
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc73
-rw-r--r--extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h79
-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/ceres/patches/collections_port.h.mingw.patch13
-rw-r--r--extern/libmv/third_party/ceres/patches/msvc_glog_fix.patch50
-rw-r--r--extern/libmv/third_party/ceres/patches/no_previous_declaration_fix.patch199
-rw-r--r--extern/libmv/third_party/ceres/patches/series3
-rw-r--r--extern/libmv/third_party/ldl/CMakeLists.txt5
-rw-r--r--extern/libmv/third_party/ldl/Doc/ChangeLog39
-rw-r--r--extern/libmv/third_party/ldl/Doc/lesser.txt504
-rw-r--r--extern/libmv/third_party/ldl/Include/ldl.h104
-rw-r--r--extern/libmv/third_party/ldl/README.libmv10
-rw-r--r--extern/libmv/third_party/ldl/README.txt136
-rw-r--r--extern/libmv/third_party/ldl/Source/ldl.c507
-rw-r--r--extern/libmv/third_party/ssba/COPYING.TXT165
-rw-r--r--extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h204
-rw-r--r--extern/libmv/third_party/ssba/Geometry/v3d_distortion.h97
-rw-r--r--extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp405
-rw-r--r--extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h352
-rw-r--r--extern/libmv/third_party/ssba/Math/v3d_linear.h923
-rw-r--r--extern/libmv/third_party/ssba/Math/v3d_linear_utils.h391
-rw-r--r--extern/libmv/third_party/ssba/Math/v3d_mathutilities.h59
-rw-r--r--extern/libmv/third_party/ssba/Math/v3d_optimization.cpp955
-rw-r--r--extern/libmv/third_party/ssba/Math/v3d_optimization.h273
-rw-r--r--extern/libmv/third_party/ssba/README.TXT92
-rw-r--r--extern/libmv/third_party/ssba/README.libmv23
-rw-r--r--extern/lzo/minilzo/COPYING29
-rw-r--r--extern/lzo/minilzo/README.LZO27
-rw-r--r--extern/lzo/minilzo/lzoconf.h79
-rw-r--r--extern/lzo/minilzo/lzodefs.h179
-rw-r--r--extern/lzo/minilzo/minilzo.c1195
-rw-r--r--extern/lzo/minilzo/minilzo.h8
-rw-r--r--intern/audaspace/FX/AUD_IDynamicIIRFilterCalculator.h2
-rw-r--r--intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp5
-rw-r--r--intern/audaspace/intern/AUD_Sequencer.h2
-rw-r--r--intern/cycles/blender/addon/properties.py1
-rw-r--r--intern/cycles/blender/addon/ui.py4
-rw-r--r--intern/cycles/blender/blender_object.cpp94
-rw-r--r--intern/cycles/render/object.cpp4
-rw-r--r--intern/elbeem/intern/ntl_geometrymodel.cpp8
-rw-r--r--intern/elbeem/intern/ntl_geometryobject.cpp7
-rw-r--r--intern/elbeem/intern/ntl_geometryobject.h2
-rw-r--r--intern/elbeem/intern/ntl_ray.cpp1
-rw-r--r--intern/elbeem/intern/ntl_ray.h3
-rw-r--r--intern/elbeem/intern/solver_main.cpp1
-rw-r--r--intern/elbeem/intern/solver_util.cpp14
-rw-r--r--intern/ffmpeg/ffmpeg_compat.h1
-rw-r--r--intern/ghost/GHOST_ISystem.h21
-rw-r--r--intern/ghost/GHOST_IWindow.h5
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp3
-rw-r--r--intern/ghost/intern/GHOST_System.cpp34
-rw-r--r--intern/ghost/intern/GHOST_System.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemCarbon.cpp1
-rw-r--r--intern/ghost/intern/GHOST_SystemCarbon.h1
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.h1
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm10
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp6
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h1
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp9
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h5
-rw-r--r--intern/ghost/intern/GHOST_Window.cpp1
-rw-r--r--intern/ghost/intern/GHOST_Window.h3
-rw-r--r--intern/ghost/intern/GHOST_WindowCarbon.h5
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.h4
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm5
-rw-r--r--intern/ghost/intern/GHOST_WindowManager.cpp3
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp11
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h4
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp61
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.h5
-rw-r--r--intern/iksolver/intern/IK_Solver.cpp2
-rw-r--r--intern/itasc/Armature.cpp2
-rw-r--r--intern/itasc/Armature.hpp2
-rw-r--r--intern/itasc/kdl/segment.cpp4
-rw-r--r--intern/locale/boost_locale_wrapper.cpp23
-rw-r--r--intern/locale/boost_locale_wrapper.h6
-rw-r--r--intern/smoke/intern/FLUID_3D.h4
-rw-r--r--intern/smoke/intern/FLUID_3D_STATIC.cpp52
-rw-r--r--intern/smoke/intern/WTURBULENCE.h2
-rw-r--r--release/scripts/modules/bl_i18n_utils/bl_extract_messages.py908
-rw-r--r--release/scripts/modules/bl_i18n_utils/bl_process_msg.py762
-rwxr-xr-xrelease/scripts/modules/bl_i18n_utils/languages_menu_utils.py96
-rwxr-xr-xrelease/scripts/modules/bl_i18n_utils/rtl_utils.py (renamed from release/scripts/modules/bl_i18n_utils/rtl_preprocess.py)72
-rw-r--r--release/scripts/modules/bl_i18n_utils/settings.py327
-rw-r--r--release/scripts/modules/bl_i18n_utils/spell_check_utils.py1048
-rwxr-xr-xrelease/scripts/modules/bl_i18n_utils/update_languages_menu.py148
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils.py1022
-rw-r--r--release/scripts/modules/bpy/utils.py27
-rw-r--r--release/scripts/modules/bpy_extras/keyconfig_utils.py37
-rw-r--r--release/scripts/modules/console/intellisense.py2
-rw-r--r--release/scripts/presets/operator/wm.collada_export/second_life_rigged.py1
-rw-r--r--release/scripts/presets/operator/wm.collada_export/second_life_static.py1
-rw-r--r--release/scripts/startup/bl_operators/object.py5
-rw-r--r--release/scripts/startup/bl_operators/rigidbody.py4
-rw-r--r--release/scripts/startup/bl_operators/wm.py37
-rw-r--r--release/scripts/startup/bl_ui/properties_object_constraint.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_fluid.py11
-rw-r--r--release/scripts/startup/bl_ui/properties_scene.py8
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py3
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py1
-rw-r--r--release/scripts/startup/bl_ui/space_userpref_keymap.py117
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py74
-rw-r--r--source/blender/blenkernel/BKE_depsgraph.h178
-rw-r--r--source/blender/blenkernel/BKE_report.h2
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h1
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h3
-rw-r--r--source/blender/blenkernel/depsgraph_private.h32
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c2
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c557
-rw-r--r--source/blender/blenkernel/intern/fcurve.c101
-rw-r--r--source/blender/blenkernel/intern/mask.c2
-rw-r--r--source/blender/blenkernel/intern/mesh.c20
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c6
-rw-r--r--source/blender/blenkernel/intern/modifier.c4
-rw-r--r--source/blender/blenkernel/intern/movieclip.c16
-rw-r--r--source/blender/blenkernel/intern/node.c7
-rw-r--r--source/blender/blenkernel/intern/pbvh.c16
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c5
-rw-r--r--source/blender/blenkernel/intern/pointcache.c2
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c42
-rw-r--r--source/blender/blenkernel/intern/scene.c53
-rw-r--r--source/blender/blenkernel/intern/seqmodifier.c8
-rw-r--r--source/blender/blenkernel/intern/sequencer.c34
-rw-r--r--source/blender/blenkernel/intern/text.c1
-rw-r--r--source/blender/blenkernel/intern/tracking.c119
-rw-r--r--source/blender/blenlib/BLI_math_geom.h5
-rw-r--r--source/blender/blenlib/BLI_utildefines.h3
-rw-r--r--source/blender/blenlib/intern/math_geom.c18
-rw-r--r--source/blender/blenlib/intern/threads.c8
-rw-r--r--source/blender/blenloader/intern/readfile.c31
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators_inline.h20
-rw-r--r--source/blender/bmesh/operators/bmo_hull.c5
-rw-r--r--source/blender/collada/ArmatureImporter.cpp4
-rw-r--r--source/blender/collada/ArmatureImporter.h3
-rw-r--r--source/blender/collada/CMakeLists.txt2
-rw-r--r--source/blender/collada/ControllerExporter.cpp57
-rw-r--r--source/blender/collada/DocumentImporter.cpp5
-rw-r--r--source/blender/collada/ExportSettings.h1
-rw-r--r--source/blender/collada/GeometryExporter.cpp230
-rw-r--r--source/blender/collada/GeometryExporter.h10
-rw-r--r--source/blender/collada/MeshImporter.cpp560
-rw-r--r--source/blender/collada/MeshImporter.h48
-rw-r--r--source/blender/collada/SConscript4
-rw-r--r--source/blender/collada/TransformReader.cpp44
-rw-r--r--source/blender/collada/collada.cpp2
-rw-r--r--source/blender/collada/collada.h1
-rw-r--r--source/blender/collada/collada_utils.cpp43
-rw-r--r--source/blender/collada/collada_utils.h22
-rw-r--r--source/blender/compositor/nodes/COM_ImageNode.cpp12
-rw-r--r--source/blender/compositor/operations/COM_TranslateOperation.h2
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c16
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c4
-rw-r--r--source/blender/editors/armature/CMakeLists.txt19
-rw-r--r--source/blender/editors/armature/armature_add.c849
-rw-r--r--source/blender/editors/armature/armature_edit.c1245
-rw-r--r--source/blender/editors/armature/armature_intern.h38
-rw-r--r--source/blender/editors/armature/armature_naming.c368
-rw-r--r--source/blender/editors/armature/armature_ops.c8
-rw-r--r--source/blender/editors/armature/armature_relations.c774
-rw-r--r--source/blender/editors/armature/armature_select.c940
-rw-r--r--source/blender/editors/armature/armature_skinning.c441
-rw-r--r--source/blender/editors/armature/armature_utils.c671
-rw-r--r--source/blender/editors/armature/editarmature.c6197
-rw-r--r--source/blender/editors/armature/editarmature_generate.c11
-rw-r--r--source/blender/editors/armature/editarmature_retarget.c13
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c9
-rw-r--r--source/blender/editors/armature/meshlaplacian.c8
-rw-r--r--source/blender/editors/armature/pose_edit.c1180
-rw-r--r--source/blender/editors/armature/pose_group.c523
-rw-r--r--source/blender/editors/armature/pose_lib.c (renamed from source/blender/editors/armature/poselib.c)10
-rw-r--r--source/blender/editors/armature/pose_select.c853
-rw-r--r--source/blender/editors/armature/pose_slide.c (renamed from source/blender/editors/armature/poseSlide.c)12
-rw-r--r--source/blender/editors/armature/pose_transform.c879
-rw-r--r--source/blender/editors/armature/pose_utils.c (renamed from source/blender/editors/armature/poseUtils.c)13
-rw-r--r--source/blender/editors/armature/poseobject.c2364
-rw-r--r--source/blender/editors/armature/reeb.c15
-rw-r--r--source/blender/editors/curve/CMakeLists.txt5
-rw-r--r--source/blender/editors/curve/SConscript9
-rw-r--r--source/blender/editors/curve/editcurve.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c3
-rw-r--r--source/blender/editors/include/ED_armature.h2
-rw-r--r--source/blender/editors/include/ED_view3d.h14
-rw-r--r--source/blender/editors/include/UI_interface.h1
-rw-r--r--source/blender/editors/interface/interface.c75
-rw-r--r--source/blender/editors/interface/interface_handlers.c292
-rw-r--r--source/blender/editors/interface/interface_intern.h11
-rw-r--r--source/blender/editors/interface/interface_layout.c4
-rw-r--r--source/blender/editors/interface/interface_ops.c218
-rw-r--r--source/blender/editors/interface/interface_templates.c3
-rw-r--r--source/blender/editors/interface/interface_widgets.c2
-rw-r--r--source/blender/editors/interface/view2d_ops.c7
-rw-r--r--source/blender/editors/io/CMakeLists.txt4
-rw-r--r--source/blender/editors/io/SConscript3
-rw-r--r--source/blender/editors/io/io_collada.c11
-rw-r--r--source/blender/editors/mesh/editface.c14
-rw-r--r--source/blender/editors/mesh/editmesh_select.c46
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c3
-rw-r--r--source/blender/editors/mesh/meshtools.c6
-rw-r--r--source/blender/editors/object/object_add.c85
-rw-r--r--source/blender/editors/object/object_constraint.c12
-rw-r--r--source/blender/editors/object/object_intern.h1
-rw-r--r--source/blender/editors/object/object_ops.c1
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/object/object_select.c4
-rw-r--r--source/blender/editors/object/object_transform.c2
-rw-r--r--source/blender/editors/object/object_vgroup.c8
-rw-r--r--source/blender/editors/physics/physics_pointcache.c26
-rw-r--r--source/blender/editors/screen/area.c8
-rw-r--r--source/blender/editors/screen/screen_ops.c10
-rw-r--r--source/blender/editors/screen/screendump.c16
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h2
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c8
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c44
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c3
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c2
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c4
-rw-r--r--source/blender/editors/space_clip/clip_buttons.c2
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c2
-rw-r--r--source/blender/editors/space_file/file_ops.c9
-rw-r--r--source/blender/editors/space_file/fsmenu.h2
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c39
-rw-r--r--source/blender/editors/space_image/image_buttons.c22
-rw-r--r--source/blender/editors/space_image/image_intern.h2
-rw-r--r--source/blender/editors/space_image/image_ops.c8
-rw-r--r--source/blender/editors/space_image/space_image.c2
-rw-r--r--source/blender/editors/space_info/info_ops.c10
-rw-r--r--source/blender/editors/space_info/info_stats.c18
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c12
-rw-r--r--source/blender/editors/space_nla/nla_edit.c4
-rw-r--r--source/blender/editors/space_node/drawnode.c7
-rw-r--r--source/blender/editors/space_node/node_add.c1
-rw-r--r--source/blender/editors/space_node/node_group.c6
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c71
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c9
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c2
-rw-r--r--source/blender/editors/space_text/text_format.c2
-rw-r--r--source/blender/editors/space_text/text_header.c25
-rw-r--r--source/blender/editors/space_text/text_ops.c26
-rw-r--r--source/blender/editors/space_view3d/drawobject.c17
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c31
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c324
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c17
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h4
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c36
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c6
-rw-r--r--source/blender/editors/transform/transform.c27
-rw-r--r--source/blender/editors/transform/transform.h3
-rw-r--r--source/blender/editors/transform/transform_conversions.c2
-rw-r--r--source/blender/editors/transform/transform_manipulator.c310
-rw-r--r--source/blender/editors/transform/transform_ops.c4
-rw-r--r--source/blender/editors/util/ed_util.c22
-rw-r--r--source/blender/editors/util/undo.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c24
-rw-r--r--source/blender/gpu/CMakeLists.txt5
-rw-r--r--source/blender/gpu/GPU_extensions.h32
-rw-r--r--source/blender/gpu/SConscript4
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c8
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c44
-rw-r--r--source/blender/gpu/intern/gpu_fixed_material.c191
-rw-r--r--source/blender/gpu/intern/gpu_material.c2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fixed_fragment.glsl169
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fixed_vertex.glsl48
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vertex.glsl6
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp6
-rw-r--r--source/blender/imbuf/intern/colormanagement.c41
-rw-r--r--source/blender/imbuf/intern/filetype.c5
-rw-r--r--source/blender/imbuf/intern/imageprocess.c6
-rw-r--r--source/blender/imbuf/intern/jp2.c2
-rw-r--r--source/blender/makesdna/DNA_action_types.h6
-rw-r--r--source/blender/makesdna/DNA_actuator_types.h6
-rw-r--r--source/blender/makesdna/DNA_anim_types.h11
-rw-r--r--source/blender/makesdna/DNA_controller_types.h5
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h4
-rw-r--r--source/blender/makesdna/DNA_defs.h2
-rw-r--r--source/blender/makesdna/DNA_group_types.h4
-rw-r--r--source/blender/makesdna/DNA_image_types.h4
-rw-r--r--source/blender/makesdna/DNA_key_types.h4
-rw-r--r--source/blender/makesdna/DNA_mask_types.h3
-rw-r--r--source/blender/makesdna/DNA_node_types.h3
-rw-r--r--source/blender/makesdna/DNA_property_types.h5
-rw-r--r--source/blender/makesdna/DNA_rigidbody_types.h4
-rw-r--r--source/blender/makesdna/DNA_sensor_types.h4
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h10
-rw-r--r--source/blender/makesdna/DNA_space_types.h9
-rw-r--r--source/blender/makesdna/DNA_text_types.h5
-rw-r--r--source/blender/makesdna/DNA_tracking_types.h4
-rw-r--r--source/blender/makesdna/DNA_vfont_types.h5
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt3
-rw-r--r--source/blender/makesrna/intern/rna_access.c12
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c7
-rw-r--r--source/blender/makesrna/intern/rna_particle.c2
-rw-r--r--source/blender/makesrna/intern/rna_render.c6
-rw-r--r--source/blender/makesrna/intern/rna_rigidbody.c19
-rw-r--r--source/blender/makesrna/intern/rna_scene.c13
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_space.c30
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c3
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c227
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache.c2
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c5
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c1
-rw-r--r--source/blender/nodes/intern/node_exec.c5
-rw-r--r--source/blender/python/intern/bpy_rna.c33
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c3
-rw-r--r--source/blender/render/CMakeLists.txt3
-rw-r--r--source/blender/render/intern/raytrace/reorganize.h3
-rw-r--r--source/blender/render/intern/source/occlusion.c416
-rw-r--r--source/blender/render/intern/source/pipeline.c2
-rw-r--r--source/blender/windowmanager/WM_api.h2
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c19
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c11
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c7
-rw-r--r--source/blenderplayer/CMakeLists.txt1
-rw-r--r--source/creator/CMakeLists.txt3
-rw-r--r--source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp2
-rw-r--r--source/gameengine/CMakeLists.txt1
-rw-r--r--source/gameengine/Converter/BL_BlenderDataConversion.cpp8
-rw-r--r--source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp10
-rw-r--r--source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h4
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Application.cpp48
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Application.h36
-rw-r--r--source/gameengine/Ketsji/BL_Action.cpp26
-rw-r--r--source/gameengine/Ketsji/BL_BlenderShader.cpp4
-rw-r--r--source/gameengine/Ketsji/CMakeLists.txt12
-rw-r--r--source/gameengine/Ketsji/KX_IpoConvert.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_IpoConvert.h2
-rw-r--r--source/gameengine/Physics/common/CMakeLists.txt55
-rw-r--r--source/gameengine/Physics/common/PHY_IController.cpp38
-rw-r--r--source/gameengine/Physics/common/PHY_IController.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IGraphicController.cpp38
-rw-r--r--source/gameengine/Physics/common/PHY_IGraphicController.h1
-rw-r--r--source/gameengine/Physics/common/PHY_IMotionState.cpp37
-rw-r--r--source/gameengine/Physics/common/PHY_IMotionState.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsController.cpp38
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsController.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsEnvironment.cpp46
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IVehicle.cpp10
-rw-r--r--source/gameengine/Physics/common/PHY_IVehicle.h2
-rw-r--r--source/gameengine/Physics/common/SConscript40
-rw-r--r--source/gameengine/Rasterizer/RAS_IRasterizer.h2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp16
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h3
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp8
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.h3
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp8
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h3
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp17
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h5
-rw-r--r--source/gameengine/Rasterizer/SConscript5
-rw-r--r--source/gameengine/SConscript1
-rw-r--r--source/tests/CMakeLists.txt4
-rw-r--r--source/tests/bl_keymap_completeness.py84
516 files changed, 26387 insertions, 23417 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c50caa4a348..abfdcd38954 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1971,20 +1971,27 @@ elseif(CMAKE_CXX_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)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_NO_UNKNOWN_PRAGMAS -Wno-unknown-pragmas)
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_NO_CHAR_SUBSCRIPTS -Wno-char-subscripts)
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)
- ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_UNUSED_MACROS -Wunused-macros)
+ ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_UNUSED_PARAMETER -Wunused-parameter)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_ALL -Wall)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_AUTOLOGICAL_COMPARE -Wno-tautological-compare)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_UNKNOWN_PRAGMAS -Wno-unknown-pragmas)
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_OVERLOADED_VIRTUAL -Wno-overloaded-virtual) # we get a lot of these, if its a problem a dev needs to look into it.
+ ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_SIGN_COMPARE -Wno-sign-compare)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_INVALID_OFFSETOF -Wno-invalid-offsetof)
- ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_UNUSED_MACROS -Wunused-macros)
+
+ # gives too many unfixable warnings
+ # ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_UNUSED_MACROS -Wunused-macros)
+ # ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_UNUSED_MACROS -Wunused-macros)
elseif(CMAKE_C_COMPILER_ID MATCHES "Intel")
diff --git a/SConstruct b/SConstruct
index aa84fed262b..983d534e93a 100644
--- a/SConstruct
+++ b/SConstruct
@@ -528,11 +528,13 @@ if B.targets != ['cudakernels']:
data_to_c_simple("release/datafiles/preview_cycles.blend")
# --- glsl ---
+ data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fixed_fragment.glsl")
+ data_to_c_simple("source/blender/gpu/shaders/gpu_shader_fixed_vertex.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_vertex.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_material.glsl")
+ data_to_c_simple("source/blender/gpu/shaders/gpu_shader_vertex.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")
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index 5175eb9a4f6..490c976655d 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -796,6 +796,11 @@ compile_OIIO() {
cmake_d="$cmake_d -D CMAKE_PREFIX_PATH=$_inst"
cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$_inst"
cmake_d="$cmake_d -D BUILDSTATIC=ON"
+
+ # Optional tests and cmd tools
+ cmake_d="$cmake_d -D USE_QT=OFF"
+ cmake_d="$cmake_d -D OIIO_BUILD_TOOLS=OFF"
+ cmake_d="$cmake_d -D OIIO_BUILD_TESTS=OFF"
# linking statically could give issues on Debian/Ubuntu (and probably other distros
# which doesn't like static linking) when linking shared oiio library due to missing
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index bdd82a4f438..56ac48bfa61 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -143,7 +143,9 @@ macro(blender_source_group
foreach(_SRC ${sources})
get_filename_component(_SRC_EXT ${_SRC} EXT)
- if((${_SRC_EXT} MATCHES ".h") OR (${_SRC_EXT} MATCHES ".hpp"))
+ if((${_SRC_EXT} MATCHES ".h") OR
+ (${_SRC_EXT} MATCHES ".hpp") OR
+ (${_SRC_EXT} MATCHES ".hh"))
source_group("Header Files" FILES ${_SRC})
else()
source_group("Source Files" FILES ${_SRC})
@@ -499,6 +501,7 @@ macro(remove_strict_flags)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
remove_cc_flag("-Wunused-parameter")
remove_cc_flag("-Wunused-variable")
+ remove_cc_flag("-Werror=[^ ]+")
remove_cc_flag("-Werror")
endif()
diff --git a/doc/build_systems/cmake.txt b/doc/build_systems/cmake.txt
index b7a6bd9871e..c46978df2fa 100644
--- a/doc/build_systems/cmake.txt
+++ b/doc/build_systems/cmake.txt
@@ -7,12 +7,9 @@
1. Introduction
2. Obtaining CMake
- 3. Obtaining Dependencies
- 4. Deciding on a Build Environment
- 5. Configuring the build for the first time
- 6. Configuring the build after SVN updates
- 7. Specify alternate Python library versions and locations
-
+ 3. Building Blender
+ 4. Generic Setup
+ 5. Configuring the build after SVN updates
1. Introduction
---------------
@@ -28,36 +25,17 @@
The website also contains some documentation on CMake usage but I found
the man page alone pretty helpful.
- 3. Obtaining Dependencies
- -------------------------
-
- Check from the page
- http://www.blender.org/cms/Getting_Dependencies.135.0.html that you
- have all dependencies needed for building Blender. Note that for
- windows many of these dependencies already come in the lib/windows
- module from SVN.
-
- 4. Deciding on a Build Environment
- ----------------------------------
-
- To build Blender with the CMake scripts you first need to decide which
- build environment you feel comfortable with. This decision will also be
- influenced by the platform you are developing on. The current implementation
- have been successfully used to generate build files for the following
- environments:
+ 3. Building Blender
+ -------------------
- 1. Microsoft Visual Studio 2008. There is a free version available
- at http://http://www.microsoft.com/visualstudio/en-us/products/2008-editions/express
+ Building Blender requires obtaining a compiler, library dependencies,
+ and correct setup depending on the system. For details on how to set
+ up a build on various operating systems, see the wiki documentation:
- 2. Xcode on Mac OSX
+ http://wiki.blender.org/index.php/Dev:Doc/Building_Blender
- 3. Unix Makefiles (On Linux and Mac OSX): CMake actually creates make
- files which generates nicely color coded output and a percentage
- progress indicator.
-
-
- 5. Configuring the build for the first time
- -------------------------------------------
+ 4. Generic Setup
+ ----------------
CMake allows one to generate the build project files and binary objects
outside the source tree which can be pretty handy in working and experimenting
@@ -113,42 +91,14 @@
It is also possible to use the commandline of 'cmake' to override certain
of these settings.
- 6. Configuring the build after SVN updates
+ 5. Configuring the build after SVN updates
------------------------------------------
The $BLENDERBUILD directory maintains a file called CMakeCache.txt which
remembers the initial run's settings for subsequent generation runs. After
- every SVN update it may be a good idea to rerun the generation before building
- Blender again. Just rerun the original 'cmake' run to do this, the settings
- will be remembered. For the example above the following will do after every
- 'svn up':
-
- % cmake -G Xcode $BLENDERSOURCE
-
- 7. Specify alternate Python library versions and locations
- ----------------------------------------------------------
-
- The commandline can be used to override detected/default settings, e.g:
-
- On Unix:
- cmake -D PYTHON_LIBRARY=/usr/local/lib/python3.2/config/libpython3.2.so -D PYTHON_INCLUDE_DIR=/usr/local/include/python3.2 ../blender
- On Macs:
- cmake -D PYTHON_INCLUDE_DIRS=/System/Library/Frameworks/Python.framework/Versions/3.2/include/python3.2 -G Xcode ../blender
-
- Mote that this should only be needed once per build directory generation because it will keep the overrides in CMakeCache.txt for subsequent runs.
-
-
-
- To be continued...
-
- TODO's
- ------
-
- 1. Get CMake to create proper distribution directories for the various platforms
- like scons does.
- 2. Investigate the viability of using CPack to package installs automatically.
- 3. Refine this document and write detailed developer's document.
- 4. Make sure all options (ffmpeg, openexr, quicktime) has proper CMake support
- on the various platforms.
+ SVN updates that contain changes to the build system, rebuilding Blender will
+ automatically invoke CMake to regenerate the CMakeCache.txt and other files
+ as needed.
/Jacques Beaurain (jbinto)
+
diff --git a/doc/python_api/rst/bge.logic.rst b/doc/python_api/rst/bge.logic.rst
index 944b1ca06a0..27029914487 100644
--- a/doc/python_api/rst/bge.logic.rst
+++ b/doc/python_api/rst/bge.logic.rst
@@ -127,7 +127,7 @@ Variables
.. data:: joysticks
- A list of attached joysticks. The list size it he maximum number of supported joysticks. If no joystick is available for a given slot, the slot is set to None.
+ A list of attached :class:`~bge.types.SCA_PythonJoystick`s. The list size is the maximum number of supported joysticks. If no joystick is available for a given slot, the slot is set to None.
*****************
General functions
diff --git a/extern/carve/bundle.sh b/extern/carve/bundle.sh
index 63d32a5993d..c80bf645077 100755
--- a/extern/carve/bundle.sh
+++ b/extern/carve/bundle.sh
@@ -91,7 +91,7 @@ if(WITH_BOOST)
-DCARVE_SYSTEM_BOOST
)
- list(APPEND INC
+ list(APPEND INC_SYS
\${BOOST_INCLUDE_DIR}
)
endif()
diff --git a/extern/carve/files.txt b/extern/carve/files.txt
index c3cb9275950..1084c7f5c41 100644
--- a/extern/carve/files.txt
+++ b/extern/carve/files.txt
@@ -1,107 +1,109 @@
-include/carve/polyhedron_decl.hpp
-include/carve/geom2d.hpp
-include/carve/exact.hpp
-include/carve/triangulator_impl.hpp
-include/carve/collection.hpp
-include/carve/pointset.hpp
-include/carve/djset.hpp
-include/carve/kd_node.hpp
-include/carve/polyline.hpp
-include/carve/polyline_iter.hpp
-include/carve/geom3d.hpp
-include/carve/edge_decl.hpp
-include/carve/face_decl.hpp
+include/carve/vertex_impl.hpp
include/carve/aabb_impl.hpp
-include/carve/colour.hpp
+include/carve/csg.hpp
include/carve/pointset_iter.hpp
-include/carve/polyline_decl.hpp
-include/carve/rescale.hpp
-include/carve/mesh_impl.hpp
-include/carve/classification.hpp
-include/carve/util.hpp
-include/carve/triangulator.hpp
-include/carve/polyhedron_base.hpp
-include/carve/rtree.hpp
-include/carve/math.hpp
-include/carve/math_constants.hpp
-include/carve/octree_decl.hpp
-include/carve/input.hpp
-include/carve/mesh_ops.hpp
include/carve/debug_hooks.hpp
-include/carve/mesh_simplify.hpp
-include/carve/interpolator.hpp
-include/carve/poly_decl.hpp
-include/carve/csg.hpp
include/carve/mesh.hpp
-include/carve/carve.hpp
-include/carve/gnu_cxx.h
-include/carve/polyhedron_impl.hpp
-include/carve/poly_impl.hpp
-include/carve/aabb.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/vertex_decl.hpp
+include/carve/geom.hpp
+include/carve/collection_types.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/tag.hpp
-include/carve/tree.hpp
-include/carve/heap.hpp
+include/carve/carve.hpp
+include/carve/polyline.hpp
+include/carve/config.h
+include/carve/face_decl.hpp
include/carve/matrix.hpp
-include/carve/poly.hpp
-include/carve/vector.hpp
-include/carve/intersection.hpp
-include/carve/faceloop.hpp
+include/carve/classification.hpp
include/carve/geom_impl.hpp
-include/carve/octree_impl.hpp
-include/carve/spacetree.hpp
-include/carve/collection/unordered/std_impl.hpp
-include/carve/collection/unordered/tr1_impl.hpp
-include/carve/collection/unordered/libstdcpp_impl.hpp
-include/carve/collection/unordered/boost_impl.hpp
-include/carve/collection/unordered/vcpp_impl.hpp
-include/carve/collection/unordered/fallback_impl.hpp
-include/carve/collection/unordered.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/cbrt.h
+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/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/geom.hpp
-include/carve/vertex_impl.hpp
-include/carve/polyline_impl.hpp
-include/carve/pointset_decl.hpp
-include/carve/timing.hpp
+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/iobj.hpp
-include/carve/collection_types.hpp
-lib/carve.cpp
-lib/mesh.cpp
-lib/intersect_group.cpp
-lib/intersect_classify_common.hpp
-lib/intersect_classify_edge.cpp
-lib/intersect_classify_group.cpp
+include/carve/poly.hpp
+include/carve/external/boost/random.hpp
+include/carve/timing.hpp
+include/carve/octree_decl.hpp
+include/carve/pointset_decl.hpp
+include/carve/tag.hpp
+include/carve/collection.hpp
+include/carve/poly_impl.hpp
+lib/intersection.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/csg_collector.hpp
-lib/geom3d.cpp
lib/polyline.cpp
-lib/csg_collector.cpp
-lib/triangulator.cpp
-lib/intersect_face_division.cpp
-lib/intersect_half_classify_group.cpp
-lib/edge.cpp
-lib/math.cpp
+lib/pointset.cpp
lib/geom2d.cpp
+lib/math.cpp
+lib/intersect_half_classify_group.cpp
+lib/intersect_face_division.cpp
lib/tag.cpp
-lib/intersection.cpp
-lib/convex_hull.cpp
-lib/intersect_common.hpp
-lib/intersect_classify_common_impl.hpp
-lib/csg.cpp
-lib/intersect.cpp
+lib/aabb.cpp
+lib/intersect_classify_group.cpp
lib/csg_detail.hpp
-lib/face.cpp
-lib/pointset.cpp
+lib/mesh.cpp
lib/timing.cpp
-lib/octree.cpp
-lib/aabb.cpp
-lib/intersect_debug.hpp
+lib/geom3d.cpp
+lib/intersect_group.cpp
+lib/carve.cpp
+lib/intersect_classify_edge.cpp
+lib/csg.cpp
+lib/face.cpp
+lib/csg_collector.cpp
lib/intersect_debug.cpp
+lib/edge.cpp
+lib/intersect_classify_common_impl.hpp
+lib/octree.cpp
diff --git a/extern/carve/include/carve/csg_triangulator.hpp b/extern/carve/include/carve/csg_triangulator.hpp
index 740585571bf..5a40439271e 100644
--- a/extern/carve/include/carve/csg_triangulator.hpp
+++ b/extern/carve/include/carve/csg_triangulator.hpp
@@ -174,7 +174,7 @@ namespace carve {
double scoreQuad(edge_map_t::iterator i, edge_map_t &edge_map) {
if (!(*i).second.first || !(*i).second.second) return -1;
- return 0;
+ return -1;
}
carve::mesh::MeshSet<3>::face_t *mergeQuad(edge_map_t::iterator i, edge_map_t &edge_map) {
diff --git a/extern/carve/include/carve/geom3d.hpp b/extern/carve/include/carve/geom3d.hpp
index 90d0672b81e..faeb565b922 100644
--- a/extern/carve/include/carve/geom3d.hpp
+++ b/extern/carve/include/carve/geom3d.hpp
@@ -206,9 +206,22 @@ namespace carve {
* * +1, if a is ordered after b around, rotating about direction.
*/
inline int compareAngles(const Vector &direction, const Vector &base, const Vector &a, const Vector &b) {
- const double d1 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, a, b);
- const double d2 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, base, a);
- const double d3 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, base, b);
+ // double d1 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, a, b);
+ // double d2 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, base, a);
+ // double d3 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, base, b);
+
+#if defined(CARVE_USE_EXACT_PREDICATES)
+ // which is equivalent to the following (which eliminates a
+ // vector subtraction):
+ double d1 = carve::geom3d::orient3d(direction, b, a, carve::geom::VECTOR(0,0,0));
+ double d2 = carve::geom3d::orient3d(direction, a, base, carve::geom::VECTOR(0,0,0));
+ double d3 = carve::geom3d::orient3d(direction, b, base, carve::geom::VECTOR(0,0,0));
+#else
+ // dotcross = a . (b x c)
+ double d1 = carve::geom::dotcross(direction, b, a );
+ double d2 = carve::geom::dotcross(direction, a, base);
+ double d3 = carve::geom::dotcross(direction, b, base);
+#endif
// CASE: a and b are coplanar wrt. direction.
if (d1 == 0.0) {
diff --git a/extern/carve/include/carve/geom_impl.hpp b/extern/carve/include/carve/geom_impl.hpp
index 4463ba2bd88..044655b6c07 100644
--- a/extern/carve/include/carve/geom_impl.hpp
+++ b/extern/carve/include/carve/geom_impl.hpp
@@ -396,7 +396,7 @@ namespace carve {
// Compute a . (b x c)
return
(a.x * b.y * c.z + 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.z * b.y * c.x);
+ (a.x * c.y * b.z + a.y * c.z * b.x + a.z * c.x * b.y);
}
diff --git a/extern/carve/include/carve/input.hpp b/extern/carve/include/carve/input.hpp
index a8bc8137d6c..4223955c0fd 100644
--- a/extern/carve/include/carve/input.hpp
+++ b/extern/carve/include/carve/input.hpp
@@ -17,6 +17,9 @@
#pragma once
+#include <map>
+#include <string>
+
#include <carve/carve.hpp>
#include <carve/poly.hpp>
#include <carve/mesh.hpp>
@@ -28,6 +31,50 @@
namespace carve {
namespace input {
+ typedef std::map<std::string, std::string> Options;
+
+ static inline Options opts() {
+ return Options();
+ }
+
+ static inline Options opts(const char **kv) {
+ Options r;
+ for (size_t i = 0; kv[i] != NULL; i += 2) {
+ r[kv[i]] = kv[i+1];
+ }
+ return r;
+ }
+
+ static inline Options opts(const std::string &k1, const std::string &v1) {
+ Options r;
+ r[k1] = v1;
+ return r;
+ }
+
+ static inline Options opts(const std::string &k1, const std::string &v1,
+ const std::string &k2, const std::string &v2) {
+ Options r;
+ r[k1] = v1;
+ r[k2] = v2;
+ return r;
+ }
+
+ static inline Options opts(const std::string &k1, const std::string &v1,
+ const std::string &k2, const std::string &v2,
+ const std::string &k3, const std::string &v3) {
+ Options r;
+ r[k1] = v1;
+ r[k2] = v2;
+ r[k3] = v3;
+ return r;
+ }
+
+ static inline bool _bool(const std::string &str, bool _default = false) {
+ if (str == "true") return true;
+ if (str == "false") return false;
+ return _default;
+ }
+
struct Data {
Data() {
}
@@ -126,12 +173,18 @@ namespace carve {
faceCount = 0;
}
- carve::poly::Polyhedron *create() const {
+ carve::poly::Polyhedron *create(const Options &options) const {
return new carve::poly::Polyhedron(points, faceCount, faceIndices);
}
- carve::mesh::MeshSet<3> *createMesh() const {
- return new carve::mesh::MeshSet<3>(points, faceCount, faceIndices);
+ carve::mesh::MeshSet<3> *createMesh(const Options &options) const {
+ Options::const_iterator i;
+ carve::mesh::MeshOptions opts;
+ i = options.find("avoid_cavities");
+ if (i != options.end()) {
+ opts.avoid_cavities(_bool((*i).second));
+ }
+ return new carve::mesh::MeshSet<3>(points, faceCount, faceIndices, opts);
}
};
@@ -159,7 +212,7 @@ namespace carve {
polylines.back().second.push_back(idx);
}
- carve::line::PolylineSet *create() const {
+ carve::line::PolylineSet *create(const Options &options) const {
carve::line::PolylineSet *p = new carve::line::PolylineSet(points);
for (std::list<polyline_data_t>::const_iterator i = polylines.begin();
@@ -181,7 +234,7 @@ namespace carve {
virtual ~PointSetData() {
}
- carve::point::PointSet *create() const {
+ carve::point::PointSet *create(const Options &options) const {
carve::point::PointSet *p = new carve::point::PointSet(points);
return p;
}
@@ -214,37 +267,37 @@ namespace carve {
}
template<typename T>
- static inline T *create(Data *d) {
+ static inline T *create(Data *d, const Options &options = Options()) {
return NULL;
}
};
template<>
- inline carve::mesh::MeshSet<3> *Input::create(Data *d) {
+ inline carve::mesh::MeshSet<3> *Input::create(Data *d, const Options &options) {
PolyhedronData *p = dynamic_cast<PolyhedronData *>(d);
if (p == NULL) return NULL;
- return p->createMesh();
+ return p->createMesh(options);
}
template<>
- inline carve::poly::Polyhedron *Input::create(Data *d) {
+ inline carve::poly::Polyhedron *Input::create(Data *d, const Options &options) {
PolyhedronData *p = dynamic_cast<PolyhedronData *>(d);
if (p == NULL) return NULL;
- return p->create();
+ return p->create(options);
}
template<>
- inline carve::line::PolylineSet *Input::create(Data *d) {
+ inline carve::line::PolylineSet *Input::create(Data *d, const Options &options) {
PolylineSetData *p = dynamic_cast<PolylineSetData *>(d);
if (p == NULL) return NULL;
- return p->create();
+ return p->create(options);
}
template<>
- inline carve::point::PointSet *Input::create(Data *d) {
+ inline carve::point::PointSet *Input::create(Data *d, const Options &options) {
PointSetData *p = dynamic_cast<PointSetData *>(d);
if (p == NULL) return NULL;
- return p->create();
+ return p->create(options);
}
}
diff --git a/extern/carve/include/carve/mesh.hpp b/extern/carve/include/carve/mesh.hpp
index d4170e55133..202337b64d3 100644
--- a/extern/carve/include/carve/mesh.hpp
+++ b/extern/carve/include/carve/mesh.hpp
@@ -464,8 +464,27 @@ namespace carve {
+ struct MeshOptions {
+ bool opt_avoid_cavities;
+
+ MeshOptions() :
+ opt_avoid_cavities(false) {
+ }
+
+ MeshOptions &avoid_cavities(bool val) {
+ opt_avoid_cavities = val;
+ return *this;
+ }
+ };
+
+
+
namespace detail {
class FaceStitcher {
+ FaceStitcher();
+ FaceStitcher(const FaceStitcher &);
+ FaceStitcher &operator=(const FaceStitcher &);
+
typedef Vertex<3> vertex_t;
typedef Edge<3> edge_t;
typedef Face<3> face_t;
@@ -475,6 +494,8 @@ namespace carve {
typedef std::unordered_map<vpair_t, edgelist_t, carve::mesh::hash_vertex_pair> edge_map_t;
typedef std::unordered_map<const vertex_t *, std::set<const vertex_t *> > edge_graph_t;
+ MeshOptions opts;
+
edge_map_t edges;
edge_map_t complex_edges;
@@ -570,6 +591,8 @@ namespace carve {
void build(iter_t begin, iter_t end, std::vector<Mesh<3> *> &meshes);
public:
+ FaceStitcher(const MeshOptions &_opts);
+
template<typename iter_t>
void create(iter_t begin, iter_t end, std::vector<Mesh<3> *> &meshes);
};
@@ -623,7 +646,7 @@ namespace carve {
~Mesh();
template<typename iter_t>
- static void create(iter_t begin, iter_t end, std::vector<Mesh<ndim> *> &meshes);
+ static void create(iter_t begin, iter_t end, std::vector<Mesh<ndim> *> &meshes, const MeshOptions &opts);
aabb_t getAABB() const {
return aabb_t(faces.begin(), faces.end());
@@ -692,7 +715,7 @@ namespace carve {
MeshSet &operator=(const MeshSet &);
template<typename iter_t>
- void _init_from_faces(iter_t begin, iter_t end);
+ void _init_from_faces(iter_t begin, iter_t end, const MeshOptions &opts);
public:
typedef Vertex<ndim> vertex_t;
@@ -781,13 +804,16 @@ namespace carve {
MeshSet(const std::vector<typename vertex_t::vector_t> &points,
size_t n_faces,
- const std::vector<int> &face_indices);
+ const std::vector<int> &face_indices,
+ const MeshOptions &opts = MeshOptions());
// Construct a mesh set from a set of disconnected faces. Takes
// posession of the face pointers.
- MeshSet(std::vector<face_t *> &faces);
+ MeshSet(std::vector<face_t *> &faces,
+ const MeshOptions &opts = MeshOptions());
- MeshSet(std::list<face_t *> &faces);
+ MeshSet(std::list<face_t *> &faces,
+ const MeshOptions &opts = MeshOptions());
MeshSet(std::vector<vertex_t> &_vertex_storage,
std::vector<mesh_t *> &_meshes);
@@ -817,6 +843,8 @@ namespace carve {
void collectVertices();
void canonicalize();
+
+ void separateMeshes();
};
diff --git a/extern/carve/include/carve/mesh_impl.hpp b/extern/carve/include/carve/mesh_impl.hpp
index d55df8c8130..56fb6788b62 100644
--- a/extern/carve/include/carve/mesh_impl.hpp
+++ b/extern/carve/include/carve/mesh_impl.hpp
@@ -676,7 +676,7 @@ namespace carve {
template<unsigned ndim>
template<typename iter_t>
- void Mesh<ndim>::create(iter_t begin, iter_t end, std::vector<Mesh<ndim> *> &meshes) {
+ void Mesh<ndim>::create(iter_t begin, iter_t end, std::vector<Mesh<ndim> *> &meshes, const MeshOptions &opts) {
meshes.clear();
}
@@ -684,15 +684,15 @@ namespace carve {
template<>
template<typename iter_t>
- void Mesh<3>::create(iter_t begin, iter_t end, std::vector<Mesh<3> *> &meshes) {
- detail::FaceStitcher().create(begin, end, meshes);
+ void Mesh<3>::create(iter_t begin, iter_t end, std::vector<Mesh<3> *> &meshes, const MeshOptions &opts) {
+ detail::FaceStitcher(opts).create(begin, end, meshes);
}
template<unsigned ndim>
template<typename iter_t>
- void MeshSet<ndim>::_init_from_faces(iter_t begin, iter_t end) {
+ void MeshSet<ndim>::_init_from_faces(iter_t begin, iter_t end, const MeshOptions &opts) {
typedef std::unordered_map<const vertex_t *, size_t> map_t;
map_t vmap;
@@ -723,7 +723,7 @@ namespace carve {
} while (e != f->edge);
}
- mesh_t::create(begin, end, meshes);
+ mesh_t::create(begin, end, meshes, opts);
for (size_t i = 0; i < meshes.size(); ++i) {
meshes[i]->meshset = this;
@@ -735,7 +735,8 @@ namespace carve {
template<unsigned ndim>
MeshSet<ndim>::MeshSet(const std::vector<typename MeshSet<ndim>::vertex_t::vector_t> &points,
size_t n_faces,
- const std::vector<int> &face_indices) {
+ const std::vector<int> &face_indices,
+ const MeshOptions &opts) {
vertex_storage.reserve(points.size());
std::vector<face_t *> faces;
faces.reserve(n_faces);
@@ -755,7 +756,7 @@ namespace carve {
faces.push_back(new face_t(v.begin(), v.end()));
}
CARVE_ASSERT(p == face_indices.size());
- mesh_t::create(faces.begin(), faces.end(), meshes);
+ mesh_t::create(faces.begin(), faces.end(), meshes, opts);
for (size_t i = 0; i < meshes.size(); ++i) {
meshes[i]->meshset = this;
@@ -765,15 +766,15 @@ namespace carve {
template<unsigned ndim>
- MeshSet<ndim>::MeshSet(std::vector<face_t *> &faces) {
- _init_from_faces(faces.begin(), faces.end());
+ MeshSet<ndim>::MeshSet(std::vector<face_t *> &faces, const MeshOptions &opts) {
+ _init_from_faces(faces.begin(), faces.end(), opts);
}
template<unsigned ndim>
- MeshSet<ndim>::MeshSet(std::list<face_t *> &faces) {
- _init_from_faces(faces.begin(), faces.end());
+ MeshSet<ndim>::MeshSet(std::list<face_t *> &faces, const MeshOptions &opts) {
+ _init_from_faces(faces.begin(), faces.end(), opts);
}
@@ -1010,5 +1011,41 @@ namespace carve {
vertex_storage.swap(vout);
}
+
+
+ template<unsigned ndim>
+ void MeshSet<ndim>::separateMeshes() {
+ size_t n;
+ typedef std::unordered_map<std::pair<mesh_t *, vertex_t *>, vertex_t *> vmap_t;
+ vmap_t vmap;
+ typename vmap_t::iterator vmap_iter;
+
+ for (face_iter i = faceBegin(); i != faceEnd(); ++i) {
+ face_t *f = *i;
+ for (typename face_t::edge_iter_t j = f->begin(); j != f->end(); ++j) {
+ edge_t &e = *j;
+ vmap[std::make_pair(f->mesh, e.vert)] = e.vert;
+ }
+ }
+
+ std::vector<vertex_t> vout;
+ vout.reserve(vmap.size());
+
+ for (n = 0, vmap_iter = vmap.begin(); vmap_iter != vmap.end(); ++vmap_iter, ++n) {
+ vout.push_back(*(*vmap_iter).second);
+ (*vmap_iter).second = & vout.back();
+ }
+
+ for (face_iter i = faceBegin(); i != faceEnd(); ++i) {
+ face_t *f = *i;
+ for (typename face_t::edge_iter_t j = f->begin(); j != f->end(); ++j) {
+ edge_t &e = *j;
+ e.vert = vmap[std::make_pair(f->mesh, e.vert)];
+ }
+ }
+
+ vertex_storage.swap(vout);
+ }
+
}
}
diff --git a/extern/carve/lib/intersect.cpp b/extern/carve/lib/intersect.cpp
index b92dbcfe24c..b468e4addc7 100644
--- a/extern/carve/lib/intersect.cpp
+++ b/extern/carve/lib/intersect.cpp
@@ -1320,8 +1320,8 @@ void carve::csg::CSG::calc(meshset_t *a,
}
#endif
- checkFaceLoopIntegrity(a_face_loops);
- checkFaceLoopIntegrity(b_face_loops);
+ // checkFaceLoopIntegrity(a_face_loops);
+ // checkFaceLoopIntegrity(b_face_loops);
#if defined(CARVE_DEBUG)
std::cerr << "classify" << std::endl;
diff --git a/extern/carve/lib/intersect_face_division.cpp b/extern/carve/lib/intersect_face_division.cpp
index c5d5d8c5152..3b771bc8f3e 100644
--- a/extern/carve/lib/intersect_face_division.cpp
+++ b/extern/carve/lib/intersect_face_division.cpp
@@ -1110,8 +1110,7 @@ namespace {
}
// copy up to the end of the path.
- if (pos < e1_1)
- std::copy(base_loop.begin() + pos, base_loop.begin() + e1_1, std::back_inserter(out));
+ std::copy(base_loop.begin() + pos, base_loop.begin() + e1_1, std::back_inserter(out));
CARVE_ASSERT(base_loop[e1_1] == p1.back());
std::copy(p1.rbegin(), p1.rend() - 1, std::back_inserter(out));
diff --git a/extern/carve/lib/mesh.cpp b/extern/carve/lib/mesh.cpp
index 55ab893c10a..ae91b385d44 100644
--- a/extern/carve/lib/mesh.cpp
+++ b/extern/carve/lib/mesh.cpp
@@ -243,15 +243,20 @@ namespace carve {
bool FaceStitcher::EdgeOrderData::Cmp::operator()(const EdgeOrderData &a, const EdgeOrderData &b) const {
int v = carve::geom3d::compareAngles(edge_dir, base_dir, a.face_dir, b.face_dir);
- double da = carve::geom3d::antiClockwiseAngle(base_dir, a.face_dir, edge_dir);
- double db = carve::geom3d::antiClockwiseAngle(base_dir, b.face_dir, edge_dir);
- int v0 = v;
- v = 0;
- if (da < db) v = -1;
- if (db < da) v = +1;
- if (v0 != v) {
- std::cerr << "v0= " << v0 << " v= " << v << " da= " << da << " db= " << db << " " << edge_dir << " " << base_dir << " " << a.face_dir << b.face_dir << std::endl;
+
+#if defined(CARVE_DEBUG)
+ {
+ double da = carve::geom3d::antiClockwiseAngle(base_dir, a.face_dir, edge_dir);
+ double db = carve::geom3d::antiClockwiseAngle(base_dir, b.face_dir, edge_dir);
+ int v_cmp = 0;
+ if (da < db) v_cmp = -1;
+ if (db < da) v_cmp = +1;
+ if (v_cmp != v) {
+ std::cerr << "v= " << v << " v_cmp= " << v_cmp << " da= " << da << " db= " << db << " edge_dir=" << edge_dir << " base_dir=" << base_dir << " a=" << a.face_dir << " b=" << b.face_dir << std::endl;
+ }
}
+#endif
+
if (v < 0) return true;
if (v == 0) {
if (a.is_reversed && !b.is_reversed) return true;
@@ -327,9 +332,14 @@ namespace carve {
CARVE_ASSERT(erev[0][i]->v2() == erev[j][i]->v2());
}
- std::sort(result[i].begin(),
- result[i].end(),
- EdgeOrderData::Cmp(base->v2()->v - base->v1()->v, result[i][0].face_dir));
+ geom::vector<3> sort_dir;
+ if (opts.opt_avoid_cavities) {
+ sort_dir = base->v1()->v - base->v2()->v;
+ } else {
+ sort_dir = base->v2()->v - base->v1()->v;
+ }
+
+ std::sort(result[i].begin(), result[i].end(), EdgeOrderData::Cmp(sort_dir, result[i][0].face_dir));
}
}
@@ -751,11 +761,15 @@ namespace carve {
}
}
}
+
+ FaceStitcher::FaceStitcher(const MeshOptions &_opts) : opts(_opts) {
+ }
}
}
+
// construct a MeshSet from a Polyhedron, maintaining on the
// connectivity information in the Polyhedron.
mesh::MeshSet<3> *meshFromPolyhedron(const poly::Polyhedron *poly, int manifold_id) {
diff --git a/extern/carve/lib/polyhedron.cpp b/extern/carve/lib/polyhedron.cpp
index 93e667ffaf7..43d08b81bfd 100644
--- a/extern/carve/lib/polyhedron.cpp
+++ b/extern/carve/lib/polyhedron.cpp
@@ -233,7 +233,7 @@ namespace carve {
}
std::vector<mesh::Mesh<3> *> meshes;
- mesh::Mesh<3>::create(mesh_faces.begin(), mesh_faces.end(), meshes);
+ mesh::Mesh<3>::create(mesh_faces.begin(), mesh_faces.end(), meshes, mesh::MeshOptions());
mesh::MeshSet<3> *meshset = new mesh::MeshSet<3>(vertex_storage, meshes);
manifold_is_closed.resize(meshset->meshes.size());
diff --git a/extern/carve/patches/series b/extern/carve/patches/series
index 585d90659bd..0b1f731805e 100644
--- a/extern/carve/patches/series
+++ b/extern/carve/patches/series
@@ -1,4 +1,3 @@
-strict_flags.patch
includes.patch
win32.patch
mesh_iterator.patch
diff --git a/extern/carve/patches/strict_flags.patch b/extern/carve/patches/strict_flags.patch
deleted file mode 100644
index c1046b78c5f..00000000000
--- a/extern/carve/patches/strict_flags.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-diff -r 47dfdaff1dd5 include/carve/csg_triangulator.hpp
---- a/include/carve/csg_triangulator.hpp Thu Jan 12 15:49:04 2012 -0500
-+++ b/include/carve/csg_triangulator.hpp Fri Jan 13 03:13:32 2012 +0600
-@@ -174,6 +174,7 @@
-
- double scoreQuad(edge_map_t::iterator i, edge_map_t &edge_map) {
- if (!(*i).second.first || !(*i).second.second) return -1;
-+ return 0;
- }
-
- carve::mesh::MeshSet<3>::face_t *mergeQuad(edge_map_t::iterator i, edge_map_t &edge_map) {
-diff -r 47dfdaff1dd5 lib/selfintersect.cpp
---- a/lib/selfintersect.cpp Thu Jan 12 15:49:04 2012 -0500
-+++ b/lib/selfintersect.cpp Fri Jan 13 03:13:32 2012 +0600
-@@ -465,6 +465,7 @@
-
- // returns true if no intersection, based upon edge^a_i and edge^b_j separating axis.
- bool sat_edge(const vec3 tri_a[3], const vec3 tri_b[3], unsigned i, unsigned j) {
-+ return false;
- }
-
-
diff --git a/extern/libmv/CMakeLists.txt b/extern/libmv/CMakeLists.txt
index 0fc90fdd9b9..a4910d94a37 100644
--- a/extern/libmv/CMakeLists.txt
+++ b/extern/libmv/CMakeLists.txt
@@ -28,14 +28,11 @@
set(INC
.
- ../colamd/Include
third_party/ceres/include
)
set(INC_SYS
../Eigen3
- third_party/ssba
- third_party/ldl/Include
${PNG_INCLUDE_DIR}
${ZLIB_INCLUDE_DIRS}
)
@@ -62,7 +59,6 @@ set(SRC
libmv/simple_pipeline/pipeline.cc
libmv/simple_pipeline/reconstruction.cc
libmv/simple_pipeline/resect.cc
- libmv/simple_pipeline/rigid_registration.cc
libmv/simple_pipeline/tracks.cc
libmv/tracking/brute_region_tracker.cc
libmv/tracking/esm_region_tracker.cc
@@ -83,9 +79,6 @@ set(SRC
third_party/gflags/gflags.cc
third_party/gflags/gflags_completions.cc
third_party/gflags/gflags_reporting.cc
- third_party/ldl/Source/ldl.c
- third_party/ssba/Geometry/v3d_metricbundle.cpp
- third_party/ssba/Math/v3d_optimization.cpp
libmv-capi.h
libmv/base/id_generator.h
@@ -105,6 +98,7 @@ set(SRC
libmv/multiview/homography.h
libmv/multiview/homography_parameterization.h
libmv/multiview/nviewtriangulation.h
+ libmv/multiview/panography.h
libmv/multiview/projection.h
libmv/multiview/resection.h
libmv/multiview/triangulation.h
@@ -123,7 +117,6 @@ set(SRC
libmv/simple_pipeline/pipeline.h
libmv/simple_pipeline/reconstruction.h
libmv/simple_pipeline/resect.h
- libmv/simple_pipeline/rigid_registration.h
libmv/simple_pipeline/tracks.h
libmv/tracking/brute_region_tracker.h
libmv/tracking/esm_region_tracker.h
@@ -143,16 +136,8 @@ set(SRC
third_party/gflags/gflags/gflags.h
third_party/gflags/mutex.h
third_party/gflags/util.h
- third_party/ldl/Include/ldl.h
third_party/msinttypes/inttypes.h
third_party/msinttypes/stdint.h
- third_party/ssba/Geometry/v3d_cameramatrix.h
- third_party/ssba/Geometry/v3d_distortion.h
- third_party/ssba/Geometry/v3d_metricbundle.h
- third_party/ssba/Math/v3d_linear.h
- third_party/ssba/Math/v3d_linear_utils.h
- third_party/ssba/Math/v3d_mathutilities.h
- third_party/ssba/Math/v3d_optimization.h
)
if(WIN32)
@@ -230,7 +215,6 @@ else()
endif()
add_definitions(
- -DV3DLIB_ENABLE_SUITESPARSE
-DGOOGLE_GLOG_DLL_DECL=
)
diff --git a/extern/libmv/ChangeLog b/extern/libmv/ChangeLog
index c52d5456c32..a4f25f83a1c 100644
--- a/extern/libmv/ChangeLog
+++ b/extern/libmv/ChangeLog
@@ -1,3 +1,256 @@
+commit 473996468a4e67e7c860169181a4ff31ce9b8c80
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Fri Mar 1 17:44:54 2013 +0600
+
+ Fixed incorrect order of arguments passing
+ to EXPECT_EQ in keyframe selection tests.
+
+commit d38ebb74693fdf5b8f0fecf62a3d8c9c53b0b84a
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Fri Mar 1 17:40:38 2013 +0600
+
+ Modal (aka tripod) solver rework
+
+ Several major things are done in this commit:
+
+ - First of all, logic of modal solver was changed.
+ We do not rely on only minimizer to take care of
+ guessing rotation for frame, but we're using
+ analytical rotation computation for point clouds
+ to obtain initial rotation.
+
+ Then this rotation is being refined using Ceres
+ minimizer and now instead of minimizing average
+ distance between points of point of two clouds,
+ minimization of reprojection error of point
+ cloud onto frame happens.
+
+ This gives quite a bit of precision improvement.
+
+ - Second bigger improvement here is using bundle
+ adjustment for a result of first step when we're
+ only estimating rotation between neighbor images
+ and reprojecting markers.
+
+ This averages error across the image sequence
+ avoiding error accumulation. Also, this will
+ tweak bundles themselves a bit for better match.
+
+ - And last bigger improvement here is support of
+ camera intrinsics refirenment.
+
+ This allowed to significantly improve solution
+ for real-life footage and results after such
+ refining are much more usable than it were before.
+
+ Thanks to Keir for the help and code review!
+
+commit 5d6c2e7a27bdd1a1b23bf289d70a9b8f62514c9a
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Fri Mar 1 17:37:35 2013 +0600
+
+ Increase verbosity level for reprojected markers info
+
+ This information is useful, but in cases when you, say,
+ working on a bundler it's annoying to scroll all the
+ information up.
+
+commit ac252bb1250b3028b9c94736b644e7ab4e7b14b8
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Fri Mar 1 17:36:19 2013 +0600
+
+ Move radial distortion code to own templated function
+
+ This shall not lead to any functional changes, just
+ avoids radial distortion code duplicated in camera
+ intrinsics and bundling code.
+
+ For fancier bundle adjustment support of different
+ distortion models this is not actually enough and
+ would need to make some bigger changes, but this
+ changes makes code a bit easier to maintain already.
+
+commit c253b794612dd529e1d3a9bd7a7c41c32c9a9abb
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Fri Mar 1 17:33:27 2013 +0600
+
+ Use threaded cost function, jacobian and linear solver
+ computation, so bundling is as fast as it could be with
+ current parameter block structure.
+
+commit 931fe37a10212b91b525d4f6eb753990a338b471
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Fri Mar 1 17:29:21 2013 +0600
+
+ Fixed comment for euclidean bundling,
+ which is now supports raidal bundling independently
+ from other intrinsics.
+
+commit 217d8e6edc3de1a853fb84275d2d2dd898e7529c
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Tue Feb 26 18:19:01 2013 +0600
+
+ Allow K1,K2 refirement combination
+
+ It is now possible to refine only radial distortion
+ with new Ceres based bundler and this new combination
+ is already used in Blender.
+
+commit d8850addc944d400f7a9c358396c437d9e4acc70
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Tue Feb 26 18:17:09 2013 +0600
+
+ Switch euclidean intersection code to use Ceres
+
+ Would not expect any significant changes in solver
+ behavior, but it could be more accurate in some cases.
+
+ Switching projective intersection to ceres is marked
+ as a TODO for now.
+
+commit 6990b7946ec96b3cb2dcfc8a1beaaba9538b0802
+Author: Keir Mierle <mierle@gmail.com>
+Date: Mon Feb 25 20:00:48 2013 +0000
+
+ Switch motion tracker bundle adjustment to Ceres.
+
+ Patch originally written by me, then finished by Sergey. Big
+ thanks to Sergey for troopering through and fixing the many issues
+ with my original (not compilable) patch.
+
+ The Ceres implementation uses 2 parameter blocks for each camera
+ (1 for rotation and 1 for translation), 1 parameter block for
+ common intrinsics (focal length etc) and 1 parameter block for
+ each track (e.g. bundle or 3D point).
+
+ We turn on some fancy optimizer options to get better performance,
+ in particular:
+
+ options.preconditioner_type = ceres::SCHUR_JACOBI;
+ options.linear_solver_type = ceres::ITERATIVE_SCHUR;
+ options.use_inner_iterations = true;
+ options.use_nonmonotonic_steps = true;
+ options.max_num_iterations = 100;
+
+ Special thanks to Sameer Agarwal of Ceres fame for splitting out
+ the SCHUR_JACOBI preconditioner so that it didn't depend on
+ CHOLMOD. Previously we could not use that preconditioner in
+ Blender because CHOLMOD is too large of a dependency for Blender.
+
+ BundleIntrinsicsLogMessage:
+ - Moved bunch of if(foo) LG << "bar" into this function, to make
+ EuclideanBundleCommonIntrinsics a little bit easier to follow.
+
+ EuclideanBundle:
+ - Fix RMSE logging.
+
+commit 1696342954614b54133780d74d6ee0fbcbe224f0
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Tue Feb 26 18:10:33 2013 +0600
+
+ Upgrade ceres to latest upstream version
+
+ This is needed because of some features of new Ceres
+ for further development.
+
+commit 575336f794841ada90aacd783285014081b8318c
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Mon Jan 7 15:58:40 2013 +0600
+
+ Fixed for keyframe selection
+
+ - Calculate residuals for GRIC in pixel space rather than
+ in normalized space.
+
+ This seems to be how it's intended to be used.
+
+ Algebraic H and F will still use normalized coordinates which
+ are more stable, after this matrices are converted to pixel
+ space and Ceres refinement happens in pixel space.
+
+ - Standard deviation calculation was wrong in GRIC. It shouldn't
+ be deviation of residuals, but as per Torr it should be deviation
+ of measurement error, which is constant (in our case 0.1)
+
+ Not sure if using squared cost function is correct for GRIC,
+ but cost function is indeed squared and in most papers cost
+ function is used for GRIC. After some further tests we could
+ switch GRIC residuals to non-squared distance.
+
+ - Bring back rho part of GRIC, in unit tests it doesn't make
+ sense whether it's enabled or not, lets see how it'll behave
+ in real-life footage.
+
+ - Added one more unit test based on elevator scene and manual
+ keyframe selection.
+
+commit 24117f3c3fc5531beb6497d79bb6f1780a998081
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Sun Jan 6 19:07:06 2013 +0600
+
+ Added test for keyframe selection based on manual selection
+
+ Additional changes:
+
+ - Reduce minimal correspondence to match real-world manually
+ tracked footage
+
+ - Returned back squares to SymmetricEpipolarDistance and
+ SymmetricGeometricDistance -- this is actually a cost
+ functions, not distances and they shall be squared.
+
+commit 770eb0293b881c4c419c587a6cdb062c47ab6e44
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Fri Dec 21 00:43:30 2012 +0600
+
+ Improvements for keyframe selection
+
+ - Changed main keyframe selection cycle, so in cases there're no
+ more next keyframes for current keyframe could be found in the
+ image sequence, current keyframe would be moved forward and
+ search continues.
+
+ This helps in cases when there's poor motion in the beginning
+ of the sequence, then markers becomes occluded. There could be
+ good keyframes in the middle of the shot still.
+
+ - Extended keyframe_selection_test with real world cases.
+
+ - Moved correspondences constraint to the top, so no H/F estimation
+ happens if there's bad correspondence. Makes algorithm go a bit
+ faster.
+
+ Strangely, but using non-squared distances makes neighbor frames
+ test fail, using squared distances makes this tests pass.
+
+ However, using non-squared distances seems to be working better
+ in real tests i've been doing. So this requires more investigation/
+
+commit 7415c62fbda36c5bd1c291bc94d535a66da896d0
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Thu Dec 20 18:46:09 2012 +0600
+
+ Cosmetic change to correspondences reports in keyframe selection
+
+commit ceaf80c987ec0338e7e83965bc808411453eb755
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Thu Dec 20 18:08:03 2012 +0600
+
+ Various fixes:
+
+ - That was a typo in symmetric geometric cost functor, which
+ computed inverse distance in a wrong way.
+
+ - Fixed compilation of unit tests
+
+ - Added simple test for keyframe selection. Currently only
+ covers case that neighbor frames with only translation
+ (homography should be better than fundamental) are not
+ considered a keyframes.
+
+ Still need to be investigated why it only works if tracks
+ are in pixel space and why doesn't work in normalized space.
+
commit cfabdfe48df2add3d1f30cf4370efd0b31990ab0
Author: Sergey Sharybin <sergey.vfx@gmail.com>
Date: Thu Dec 20 05:46:53 2012 +0600
@@ -545,180 +798,3 @@ Date: Thu Apr 12 13:56:02 2012 +0600
It projects markers onto sphere and uses rigid registration of rotation to
find rotation angles which makes bundles from previous and current frame be
as closest as it's possible.
-
-commit fa3842e472e3b9c789e47bf6d8f592aa40a84f16
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Thu Apr 12 12:32:48 2012 +0600
-
- implementation of some basic algorithms for point cloud orientation:
-
- - Implementation of rigid registration algorithm which searches transformation
- form one point cloud to another assuming that points in this clouds are
- already paired (points with the same index in different clouds belongs to
- the same pair) which minimizes average distance between points in pairs.
-
- Algorithm uses Levenberg-Marquardt solver to find such transformation.
-
- Supports registration of rotation-scale-transform (which is probably most
- common usage) and rotation only (which might be useful for basic modal
- tripod solver).
-
- - Implementation of Iterative-Point-Clouds algorithm which searches
- transformation from one arbitrary point cloud to another making
- points as closest to each other as possible.
-
- This algorithm doesn't require points be initially paired, but for
- good result clouds should have rough initial orientation. If they're
- arbitrary oriented from the very beginning, algorithm might fail
- producing good resold.
-
- Iteration is based on building pairs of closest to each other points
- and registering rigid transformation between them which incrementally
- constructs final result.
-
- TODO: building pairs might be speedup a lot using data structures like
- AABB trees, K-D trees or so.
-
-commit 9618d9a1d48bb3c28da605d9027f57a74f462785
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Wed Apr 11 14:17:14 2012 +0600
-
- Added configuration file for glog to compile smooth on Hurd platform.
-
- Patch by Pino Toscano <pino@debian.org>, thanks!
-
-commit 63b2bd20237c8599fa73ce42556e4fb99b9f7cca
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Thu Mar 22 17:03:34 2012 +0600
-
- Trackers refactoring:
- - Deduplicate pattern sampling used in esm and lmicklt trackers
- and move SamplePattern to image/sample.h
- - Move computation of Pearson product-moment correlation into
- own function in new file image/correlation.h so all trackers
- can use it to check final correlation.
- - Remove SAD tracker. It's almost the same as brute tracker,
- with only two differences:
- 1. It does brute search of affine transformation which in some cases
- helps to track rotating features
- 2. It didn't use common tracker api which probably gave some speed
- advantage, but lead to a real headache to use it together with
- other trackers leading to duplicated code in 3d-party software.
-
-commit 9fe49c32e990f28c83f2bbb1d18057aed8879af7
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Mon Mar 12 09:36:15 2012 +0600
-
- Code cleanup: convert line endings to Unix style (native on my platform) so it
- wouldn't confuse other versioning systems used for project where libmv is bundled to,
-
- Also change mode to +x for glog's windows-related script.
-
-commit fe74ae2b53769389b0ed9d7e604c8e60be81077d
-Author: Sergey I. Sharybin <g.ulairi@gmail.com>
-Date: Sun Mar 11 20:34:15 2012 +0600
-
- Replace "third_party/glog/src/glog/logging.h" with <glog/logging.h>
-
- It was needed because of how build systems is setup in Blender but think
- this will be helpful change for other applications too because it makes
- it's easier to move libraries around and even use libraries installed
- on the operation system.
-
-commit 37fc726701479f2d321d6af878fa93f3176278d5
-Author: Sergey I. Sharybin <g.ulairi@gmail.com>
-Date: Sun Mar 11 19:27:41 2012 +0600
-
- Upgrade gflags and glog libraries - stage 2 (final)
-
- Changes to upstream code which are needed to make libmv compile smooth on all platforms
-
- * Replace <gflags/gflags.h> with "third_party/gflags/gflags/gflags.h" which is easier
- to setup things in libmv and also helps with setting up building libmv into
- external applications.
- * Replace "glog/logging.h" and "glog/logging.h" with <glog/logging.h> and <glog/logging.h>
- which is needed on Windows platform because otherwise files like logging.cc will be using
- relative path which points to headers used by linux instead of headers need to be used
- on Windows.
- * Replace _asm int 3 with __debugbreak(). Such assembler code is obsolete and doesn't work
- with 64bit versions of MSVC compilers.
- * Do not use stacktrace for MinGW and FreeBSD because it leads into issues accessing
- some specific data on this platforms.
- * Define HAVE_LIB_GFLAGS for Windows builds.
- * Do not define __declspec(dllimport) for MinGW platforms.
- * Setup proper includes and datatypes for int32, uint32, int64 and uint64 for MinGW
- * Do not define va_copy for MinGW platforms (it's already defined there).
- * Patch localtime_r to be working fine with MinGW, disable strerror_r for MinGW because
- of lack of needed functions.
-
-commit 8ed07abfa49d1e0511752021c972e0715e5a1383
-Author: Sergey I. Sharybin <g.ulairi@gmail.com>
-Date: Sun Mar 11 19:06:33 2012 +0600
-
- Upgrade gflags and glog libraries - stage 1
-
- This commit copies sources from latest original release of gflags and glog
- over currently bundled versions of this libraries without any modifications.
-
- This revision can't b compiled, all needed changes to make new libraries working
- fine will be done with next commit to make it clear which changes were necessary
- for easier bundling further newer version and extract patches and put them to
- gflags/glog upstream repo.
-
- Such upgrade of libraries is needed to make it able to compile libmv
- with clang compilers. Currently used versions:
-
- - gflags is version 2.0
- - glog is version 0.3.2
-
-commit 75b9af405964ff2c7d3f0a44500e27e63b37c91b
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 17 23:29:11 2012 +0600
-
- _USE_MATH_DEFINES is needed to define constants like M_E when building with msvc
- Occasionally was removed, but now added comment about this so hopefully it
- wouldn't removed again.
-
-commit f85b1232a9b929f69443b5eed6e7a39908cd6551
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 17 21:34:40 2012 +0600
-
- Picky edit: corrected mode for ssba readme file.
-
-commit f8c2b223f01551fd81a85f6d5221646165147035
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 17 21:32:05 2012 +0600
-
- Picky edits: corrected EOL
-
-commit 3f2a4205ec5adadcdfa306b161c705c868a7be93
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 17 21:30:07 2012 +0600
-
- Fixed incorrect access to ucontext on linux. Caused by incorrect merge conflict resolve.
-
-commit d360a21a5aa125cf9e83dd26b302508688ff7007
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 17 20:54:13 2012 +0600
-
- More Windows -> Unix EOL conversions
-
-commit 18aeda58bec9556140ba617724e31ada6f5b67c0
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 17 20:15:42 2012 +0600
-
- Looks like this debug output was removed accidentally.
-
-commit 189dc0cacdee3c1eab68c43263ecb038ed244c09
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 17 20:11:56 2012 +0600
-
- Made V3D verbose again by default
-
-commit 8b3422d3eec5e450d76243886bf07fb0a3e83a81
-Author: Sergey Sharybin <sergey.vfx@gmail.com>
-Date: Fri Feb 17 20:08:01 2012 +0600
-
- SAD tracker now can deal with pattern size any size,
- Very quick implementation came from Blender before Hybrid tracker was added.
- Better to be replaced with brute tracker.
diff --git a/extern/libmv/SConscript b/extern/libmv/SConscript
index 8fd8c566e4d..d0015db42d7 100644
--- a/extern/libmv/SConscript
+++ b/extern/libmv/SConscript
@@ -11,7 +11,6 @@ Import('env')
defs = []
-defs.append('V3DLIB_ENABLE_SUITESPARSE')
defs.append('GOOGLE_GLOG_DLL_DECL=')
src = env.Glob("*.cpp")
@@ -22,9 +21,6 @@ src += env.Glob('libmv/simple_pipeline/*.cc')
src += env.Glob('libmv/tracking/*.cc')
src += env.Glob('third_party/fast/*.c')
src += env.Glob('third_party/gflags/*.cc')
-src += env.Glob('third_party/ldl/Source/*.c')
-src += env.Glob('third_party/ssba/Geometry/*.cpp')
-src += env.Glob('third_party/ssba/Math/*.cpp')
incs = '. ../Eigen3 third_party/ceres/include'
incs += ' ' + env['BF_PNG_INC']
@@ -41,8 +37,6 @@ else:
src += env.Glob("third_party/glog/src/*.cc")
incs += ' ./third_party/glog/src'
-incs += ' ./third_party/ssba ./third_party/ldl/Include ../colamd/Include'
-
env.BlenderLib ( libname = 'extern_libmv', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137] )
SConscript(['third_party/SConscript'])
diff --git a/extern/libmv/bundle.sh b/extern/libmv/bundle.sh
index 53487cf020e..a9edfde55bf 100755
--- a/extern/libmv/bundle.sh
+++ b/extern/libmv/bundle.sh
@@ -124,14 +124,11 @@ cat > CMakeLists.txt << EOF
set(INC
.
- ../colamd/Include
third_party/ceres/include
)
set(INC_SYS
../Eigen3
- third_party/ssba
- third_party/ldl/Include
\${PNG_INCLUDE_DIR}
\${ZLIB_INCLUDE_DIRS}
)
@@ -197,7 +194,6 @@ ${third_glog_headers}
endif()
add_definitions(
- -DV3DLIB_ENABLE_SUITESPARSE
-DGOOGLE_GLOG_DLL_DECL=
)
@@ -220,7 +216,6 @@ Import('env')
defs = []
-defs.append('V3DLIB_ENABLE_SUITESPARSE')
defs.append('GOOGLE_GLOG_DLL_DECL=')
src = env.Glob("*.cpp")
@@ -241,8 +236,6 @@ else:
src += env.Glob("third_party/glog/src/*.cc")
incs += ' ./third_party/glog/src'
-incs += ' ./third_party/ssba ./third_party/ldl/Include ../colamd/Include'
-
env.BlenderLib ( libname = 'extern_libmv', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137] )
SConscript(['third_party/SConscript'])
diff --git a/extern/libmv/files.txt b/extern/libmv/files.txt
index 22c5226adbe..16afdb36371 100644
--- a/extern/libmv/files.txt
+++ b/extern/libmv/files.txt
@@ -21,6 +21,7 @@ libmv/multiview/homography.cc
libmv/multiview/homography.h
libmv/multiview/homography_parameterization.h
libmv/multiview/nviewtriangulation.h
+libmv/multiview/panography.h
libmv/multiview/projection.cc
libmv/multiview/projection.h
libmv/multiview/resection.h
@@ -53,8 +54,6 @@ libmv/simple_pipeline/reconstruction.cc
libmv/simple_pipeline/reconstruction.h
libmv/simple_pipeline/resect.cc
libmv/simple_pipeline/resect.h
-libmv/simple_pipeline/rigid_registration.cc
-libmv/simple_pipeline/rigid_registration.h
libmv/simple_pipeline/tracks.cc
libmv/simple_pipeline/tracks.h
libmv/tracking/brute_region_tracker.cc
@@ -142,25 +141,6 @@ 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/ldl/CMakeLists.txt
-third_party/ldl/Doc/ChangeLog
-third_party/ldl/Doc/lesser.txt
-third_party/ldl/Include/ldl.h
-third_party/ldl/README.libmv
-third_party/ldl/README.txt
-third_party/ldl/Source/ldl.c
third_party/msinttypes/inttypes.h
third_party/msinttypes/README.libmv
third_party/msinttypes/stdint.h
-third_party/ssba/COPYING.TXT
-third_party/ssba/Geometry/v3d_cameramatrix.h
-third_party/ssba/Geometry/v3d_distortion.h
-third_party/ssba/Geometry/v3d_metricbundle.cpp
-third_party/ssba/Geometry/v3d_metricbundle.h
-third_party/ssba/Math/v3d_linear.h
-third_party/ssba/Math/v3d_linear_utils.h
-third_party/ssba/Math/v3d_mathutilities.h
-third_party/ssba/Math/v3d_optimization.cpp
-third_party/ssba/Math/v3d_optimization.h
-third_party/ssba/README.libmv
-third_party/ssba/README.TXT
diff --git a/extern/libmv/libmv-capi.cpp b/extern/libmv/libmv-capi.cpp
index 8e483abd386..a85c3268b16 100644
--- a/extern/libmv/libmv-capi.cpp
+++ b/extern/libmv/libmv-capi.cpp
@@ -34,21 +34,8 @@
#include "libmv-capi.h"
-#include "third_party/gflags/gflags/gflags.h"
-#include "glog/logging.h"
#include "libmv/logging/logging.h"
-#include "Math/v3d_optimization.h"
-
-#include "libmv/numeric/numeric.h"
-
-#include "libmv/tracking/esm_region_tracker.h"
-#include "libmv/tracking/brute_region_tracker.h"
-#include "libmv/tracking/hybrid_region_tracker.h"
-#include "libmv/tracking/klt_region_tracker.h"
-#include "libmv/tracking/trklt_region_tracker.h"
-#include "libmv/tracking/lmicklt_region_tracker.h"
-#include "libmv/tracking/pyramid_region_tracker.h"
#include "libmv/tracking/track_region.h"
#include "libmv/simple_pipeline/callbacks.h"
@@ -58,7 +45,6 @@
#include "libmv/simple_pipeline/detect.h"
#include "libmv/simple_pipeline/pipeline.h"
#include "libmv/simple_pipeline/camera_intrinsics.h"
-#include "libmv/simple_pipeline/rigid_registration.h"
#include "libmv/simple_pipeline/modal_solver.h"
#include <stdlib.h>
@@ -96,7 +82,6 @@ void libmv_initLogging(const char *argv0)
google::SetCommandLineOption("v", "0");
google::SetCommandLineOption("stderrthreshold", "7");
google::SetCommandLineOption("minloglevel", "7");
- V3D::optimizerVerbosenessLevel = 0;
}
void libmv_startDebugLogging(void)
@@ -105,7 +90,6 @@ void libmv_startDebugLogging(void)
google::SetCommandLineOption("v", "2");
google::SetCommandLineOption("stderrthreshold", "1");
google::SetCommandLineOption("minloglevel", "0");
- V3D::optimizerVerbosenessLevel = 1;
}
void libmv_setLoggingVerbosity(int verbosity)
@@ -114,54 +98,9 @@ void libmv_setLoggingVerbosity(int verbosity)
snprintf(val, sizeof(val), "%d", verbosity);
google::SetCommandLineOption("v", val);
- V3D::optimizerVerbosenessLevel = verbosity;
-}
-
-/* ************ RegionTracker ************ */
-
-libmv_RegionTracker *libmv_pyramidRegionTrackerNew(int max_iterations, int pyramid_level, int half_window_size, double minimum_correlation)
-{
- libmv::EsmRegionTracker *esm_region_tracker = new libmv::EsmRegionTracker;
- esm_region_tracker->half_window_size = half_window_size;
- esm_region_tracker->max_iterations = max_iterations;
- esm_region_tracker->min_determinant = 1e-4;
- esm_region_tracker->minimum_correlation = minimum_correlation;
-
- libmv::PyramidRegionTracker *pyramid_region_tracker =
- new libmv::PyramidRegionTracker(esm_region_tracker, pyramid_level);
-
- return (libmv_RegionTracker *)pyramid_region_tracker;
-}
-
-libmv_RegionTracker *libmv_hybridRegionTrackerNew(int max_iterations, int half_window_size, double minimum_correlation)
-{
- libmv::EsmRegionTracker *esm_region_tracker = new libmv::EsmRegionTracker;
- esm_region_tracker->half_window_size = half_window_size;
- esm_region_tracker->max_iterations = max_iterations;
- esm_region_tracker->min_determinant = 1e-4;
- esm_region_tracker->minimum_correlation = minimum_correlation;
-
- libmv::BruteRegionTracker *brute_region_tracker = new libmv::BruteRegionTracker;
- brute_region_tracker->half_window_size = half_window_size;
-
- /* do not use correlation check for brute checker itself,
- * this check will happen in esm tracker */
- brute_region_tracker->minimum_correlation = 0.0;
-
- libmv::HybridRegionTracker *hybrid_region_tracker =
- new libmv::HybridRegionTracker(brute_region_tracker, esm_region_tracker);
-
- return (libmv_RegionTracker *)hybrid_region_tracker;
}
-libmv_RegionTracker *libmv_bruteRegionTrackerNew(int half_window_size, double minimum_correlation)
-{
- libmv::BruteRegionTracker *brute_region_tracker = new libmv::BruteRegionTracker;
- brute_region_tracker->half_window_size = half_window_size;
- brute_region_tracker->minimum_correlation = minimum_correlation;
-
- return (libmv_RegionTracker *)brute_region_tracker;
-}
+/* ************ Utility ************ */
static void floatBufToImage(const float *buf, int width, int height, int channels, libmv::FloatImage *image)
{
@@ -303,7 +242,7 @@ static void saveBytesImage(const char *prefix, unsigned char *data, int width, i
}
{
- static int a= 0;
+ static int a = 0;
char buf[128];
snprintf(buf, sizeof(buf), "%s_%02d.png", prefix, ++a);
savePNGImage(row_pointers, width, height, 8, PNG_COLOR_TYPE_RGBA, buf);
@@ -316,43 +255,6 @@ static void saveBytesImage(const char *prefix, unsigned char *data, int width, i
}
#endif
-int libmv_regionTrackerTrack(libmv_RegionTracker *libmv_tracker, const float *ima1, const float *ima2,
- int width, int height, double x1, double y1, double *x2, double *y2)
-{
- libmv::RegionTracker *region_tracker = (libmv::RegionTracker *)libmv_tracker;
- libmv::FloatImage old_patch, new_patch;
-
- floatBufToImage(ima1, width, height, 1, &old_patch);
- floatBufToImage(ima2, width, height, 1, &new_patch);
-
-#if !defined(DUMP_FAILURE) && !defined(DUMP_ALWAYS)
- return region_tracker->Track(old_patch, new_patch, x1, y1, x2, y2);
-#else
- {
- /* double sx2 = *x2, sy2 = *y2; */
- int result = region_tracker->Track(old_patch, new_patch, x1, y1, x2, y2);
-
-#if defined(DUMP_ALWAYS)
- {
-#else
- if (!result) {
-#endif
- saveImage("old_patch", old_patch, x1, y1);
- saveImage("new_patch", new_patch, *x2, *y2);
- }
-
- return result;
- }
-#endif
-}
-
-void libmv_regionTrackerDestroy(libmv_RegionTracker *libmv_tracker)
-{
- libmv::RegionTracker *region_tracker= (libmv::RegionTracker *)libmv_tracker;
-
- delete region_tracker;
-}
-
/* ************ Planar tracker ************ */
/* TrackRegion (new planar tracker) */
@@ -523,12 +425,15 @@ int libmv_refineParametersAreValid(int parameters) {
LIBMV_REFINE_RADIAL_DISTORTION_K1 |
LIBMV_REFINE_RADIAL_DISTORTION_K2)) ||
(parameters == (LIBMV_REFINE_FOCAL_LENGTH |
- LIBMV_REFINE_RADIAL_DISTORTION_K1));
+ LIBMV_REFINE_RADIAL_DISTORTION_K1)) ||
+ (parameters == (LIBMV_REFINE_RADIAL_DISTORTION_K1 |
+ LIBMV_REFINE_RADIAL_DISTORTION_K2));
}
static void libmv_solveRefineIntrinsics(libmv::Tracks *tracks, libmv::CameraIntrinsics *intrinsics,
libmv::EuclideanReconstruction *reconstruction, int refine_intrinsics,
- reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
+ reconstruct_progress_update_cb progress_update_callback, void *callback_customdata,
+ int bundle_constraints = libmv::BUNDLE_NO_CONSTRAINTS)
{
/* only a few combinations are supported but trust the caller */
int libmv_refine_flags = 0;
@@ -549,43 +454,84 @@ static void libmv_solveRefineIntrinsics(libmv::Tracks *tracks, libmv::CameraIntr
progress_update_callback(callback_customdata, 1.0, "Refining solution");
libmv::EuclideanBundleCommonIntrinsics(*(libmv::Tracks *)tracks, libmv_refine_flags,
- reconstruction, intrinsics);
+ reconstruction, intrinsics, bundle_constraints);
}
-libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyframe1, int keyframe2,
- int refine_intrinsics, double focal_length, double principal_x, double principal_y,
- double k1, double k2, double k3, struct libmv_reconstructionOptions *options,
- reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
+static void cameraIntrinsicsFromOptions(libmv::CameraIntrinsics *camera_intrinsics,
+ libmv_cameraIntrinsicsOptions *camera_intrinsics_options)
+{
+ 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->SetRadialDistortion(camera_intrinsics_options->k1,
+ camera_intrinsics_options->k2,
+ camera_intrinsics_options->k3);
+
+ camera_intrinsics->SetImageSize(camera_intrinsics_options->image_width,
+ camera_intrinsics_options->image_height);
+}
+
+static libmv::Tracks getNormalizedTracks(libmv::Tracks *tracks, libmv::CameraIntrinsics *camera_intrinsics)
+{
+ libmv::vector<libmv::Marker> markers = tracks->AllMarkers();
+
+ for (int i = 0; i < markers.size(); ++i) {
+ camera_intrinsics->InvertIntrinsics(markers[i].x, markers[i].y,
+ &(markers[i].x), &(markers[i].y));
+ }
+
+ return libmv::Tracks(markers);
+}
+
+static void finishReconstruction(libmv::Tracks *tracks, libmv::CameraIntrinsics *camera_intrinsics,
+ libmv_Reconstruction *libmv_reconstruction,
+ reconstruct_progress_update_cb progress_update_callback,
+ void *callback_customdata)
+{
+ libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
+
+ /* reprojection error calculation */
+ progress_update_callback(callback_customdata, 1.0, "Finishing solution");
+ libmv_reconstruction->tracks = *tracks;
+ libmv_reconstruction->error = libmv::EuclideanReprojectionError(*tracks, *reconstruction, *camera_intrinsics);
+}
+
+libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *libmv_tracks,
+ libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options,
+ libmv_reconstructionOptions *libmv_reconstruction_options,
+ reconstruct_progress_update_cb progress_update_callback,
+ void *callback_customdata)
{
- /* Invert the camera intrinsics. */
- libmv::vector<libmv::Marker> markers = ((libmv::Tracks*)tracks)->AllMarkers();
libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction();
+
+ libmv::Tracks *tracks = ((libmv::Tracks *) libmv_tracks);
libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
- libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
- libmv::ReconstructionOptions reconstruction_options;
+ libmv::CameraIntrinsics *camera_intrinsics = &libmv_reconstruction->intrinsics;
ReconstructUpdateCallback update_callback =
ReconstructUpdateCallback(progress_update_callback, callback_customdata);
- intrinsics->SetFocalLength(focal_length, focal_length);
- intrinsics->SetPrincipalPoint(principal_x, principal_y);
- intrinsics->SetRadialDistortion(k1, k2, k3);
+ cameraIntrinsicsFromOptions(camera_intrinsics, libmv_camera_intrinsics_options);
- reconstruction_options.success_threshold = options->success_threshold;
- reconstruction_options.use_fallback_reconstruction = options->use_fallback_reconstruction;
+ /* Invert the camera intrinsics */
+ libmv::Tracks normalized_tracks = getNormalizedTracks(tracks, camera_intrinsics);
- for (int i = 0; i < markers.size(); ++i) {
- intrinsics->InvertIntrinsics(markers[i].x,
- markers[i].y,
- &(markers[i].x),
- &(markers[i].y));
- }
+ /* actual reconstruction */
+ libmv::ReconstructionOptions reconstruction_options;
+ reconstruction_options.success_threshold = libmv_reconstruction_options->success_threshold;
+ reconstruction_options.use_fallback_reconstruction = libmv_reconstruction_options->use_fallback_reconstruction;
- libmv::Tracks normalized_tracks(markers);
+ int keyframe1 = libmv_reconstruction_options->keyframe1,
+ keyframe2 = libmv_reconstruction_options->keyframe2;
LG << "frames to init from: " << keyframe1 << " " << keyframe2;
+
libmv::vector<libmv::Marker> keyframe_markers =
normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2);
+
LG << "number of markers for init: " << keyframe_markers.size();
update_callback.invoke(0, "Initial reconstruction");
@@ -595,49 +541,61 @@ libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyfra
libmv::EuclideanCompleteReconstruction(reconstruction_options, normalized_tracks,
reconstruction, &update_callback);
- if (refine_intrinsics) {
- libmv_solveRefineIntrinsics((libmv::Tracks *)tracks, intrinsics, reconstruction,
- refine_intrinsics, progress_update_callback, callback_customdata);
+ /* refinement */
+ if (libmv_reconstruction_options->refine_intrinsics) {
+ libmv_solveRefineIntrinsics((libmv::Tracks *)tracks, camera_intrinsics, reconstruction,
+ libmv_reconstruction_options->refine_intrinsics,
+ progress_update_callback, callback_customdata);
}
- progress_update_callback(callback_customdata, 1.0, "Finishing solution");
- libmv_reconstruction->tracks = *(libmv::Tracks *)tracks;
- libmv_reconstruction->error = libmv::EuclideanReprojectionError(*(libmv::Tracks *)tracks, *reconstruction, *intrinsics);
+ /* finish reconstruction */
+ finishReconstruction(tracks, camera_intrinsics, libmv_reconstruction,
+ progress_update_callback, callback_customdata);
return (libmv_Reconstruction *)libmv_reconstruction;
}
-struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *tracks, double focal_length,
- double principal_x, double principal_y, double k1, double k2, double k3,
- reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
+struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *libmv_tracks,
+ libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options,
+ libmv_reconstructionOptions *libmv_reconstruction_options,
+ reconstruct_progress_update_cb progress_update_callback,
+ void *callback_customdata)
{
- /* Invert the camera intrinsics. */
- libmv::vector<libmv::Marker> markers = ((libmv::Tracks*)tracks)->AllMarkers();
libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction();
+
+ libmv::Tracks *tracks = ((libmv::Tracks *) libmv_tracks);
libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
- libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
+ libmv::CameraIntrinsics *camera_intrinsics = &libmv_reconstruction->intrinsics;
ReconstructUpdateCallback update_callback =
ReconstructUpdateCallback(progress_update_callback, callback_customdata);
- intrinsics->SetFocalLength(focal_length, focal_length);
- intrinsics->SetPrincipalPoint(principal_x, principal_y);
- intrinsics->SetRadialDistortion(k1, k2, k3);
-
- for (int i = 0; i < markers.size(); ++i) {
- intrinsics->InvertIntrinsics(markers[i].x,
- markers[i].y,
- &(markers[i].x),
- &(markers[i].y));
- }
+ cameraIntrinsicsFromOptions(camera_intrinsics, libmv_camera_intrinsics_options);
- libmv::Tracks normalized_tracks(markers);
+ /* Invert the camera intrinsics. */
+ libmv::Tracks normalized_tracks = getNormalizedTracks(tracks, camera_intrinsics);
+ /* Actual reconstruction. */
libmv::ModalSolver(normalized_tracks, reconstruction, &update_callback);
- progress_update_callback(callback_customdata, 1.0, "Finishing solution");
- libmv_reconstruction->tracks = *(libmv::Tracks *)tracks;
- libmv_reconstruction->error = libmv::EuclideanReprojectionError(*(libmv::Tracks *)tracks, *reconstruction, *intrinsics);
+ libmv::CameraIntrinsics empty_intrinsics;
+ libmv::EuclideanBundleCommonIntrinsics(normalized_tracks,
+ libmv::BUNDLE_NO_INTRINSICS,
+ reconstruction,
+ &empty_intrinsics,
+ libmv::BUNDLE_NO_TRANSLATION);
+
+ /* Refinement. */
+ if (libmv_reconstruction_options->refine_intrinsics) {
+ libmv_solveRefineIntrinsics((libmv::Tracks *)tracks, camera_intrinsics, reconstruction,
+ libmv_reconstruction_options->refine_intrinsics,
+ progress_update_callback, callback_customdata,
+ libmv::BUNDLE_NO_TRANSLATION);
+ }
+
+ /* Finish reconstruction. */
+ finishReconstruction(tracks, camera_intrinsics, libmv_reconstruction,
+ progress_update_callback, callback_customdata);
return (libmv_Reconstruction *)libmv_reconstruction;
}
@@ -863,17 +821,13 @@ struct libmv_CameraIntrinsics *libmv_ReconstructionExtractIntrinsics(struct libm
return (struct libmv_CameraIntrinsics *)&libmv_Reconstruction->intrinsics;
}
-struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(double focal_length, double principal_x, double principal_y,
- double k1, double k2, double k3, int width, int height)
+struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options)
{
- libmv::CameraIntrinsics *intrinsics= new libmv::CameraIntrinsics();
+ libmv::CameraIntrinsics *camera_intrinsics = new libmv::CameraIntrinsics();
- intrinsics->SetFocalLength(focal_length, focal_length);
- intrinsics->SetPrincipalPoint(principal_x, principal_y);
- intrinsics->SetRadialDistortion(k1, k2, k3);
- intrinsics->SetImageSize(width, height);
+ cameraIntrinsicsFromOptions(camera_intrinsics, libmv_camera_intrinsics_options);
- return (struct libmv_CameraIntrinsics *) intrinsics;
+ return (struct libmv_CameraIntrinsics *) camera_intrinsics;
}
struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsCopy(struct libmv_CameraIntrinsics *libmvIntrinsics)
@@ -891,40 +845,63 @@ void libmv_CameraIntrinsicsDestroy(struct libmv_CameraIntrinsics *libmvIntrinsic
delete intrinsics;
}
-void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmvIntrinsics, double focal_length,
- double principal_x, double principal_y, double k1, double k2, double k3, int width, int height)
+void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmv_intrinsics,
+ libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options)
{
- libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+ libmv::CameraIntrinsics *camera_intrinsics = (libmv::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;
+ double k1 = libmv_camera_intrinsics_options->k1;
+ double k2 = libmv_camera_intrinsics_options->k2;
+ double k3 = libmv_camera_intrinsics_options->k3;
+ int image_width = libmv_camera_intrinsics_options->image_width;
+ int image_height = libmv_camera_intrinsics_options->image_height;
- if (intrinsics->focal_length() != focal_length)
- intrinsics->SetFocalLength(focal_length, focal_length);
+ /* try avoid unnecessary updates so pre-computed distortion grids are not freed */
- if (intrinsics->principal_point_x() != principal_x || intrinsics->principal_point_y() != principal_y)
- intrinsics->SetPrincipalPoint(principal_x, principal_y);
+ if (camera_intrinsics->focal_length() != focal_length)
+ camera_intrinsics->SetFocalLength(focal_length, focal_length);
- if (intrinsics->k1() != k1 || intrinsics->k2() != k2 || intrinsics->k3() != k3)
- intrinsics->SetRadialDistortion(k1, k2, k3);
+ if (camera_intrinsics->principal_point_x() != principal_x ||
+ camera_intrinsics->principal_point_y() != principal_y)
+ {
+ camera_intrinsics->SetPrincipalPoint(principal_x, principal_y);
+ }
- if (intrinsics->image_width() != width || intrinsics->image_height() != height)
- intrinsics->SetImageSize(width, height);
+ if (camera_intrinsics->k1() != k1 ||
+ camera_intrinsics->k2() != k2 ||
+ camera_intrinsics->k3() != k3)
+ {
+ camera_intrinsics->SetRadialDistortion(k1, k2, k3);
+ }
+
+ if (camera_intrinsics->image_width() != image_width ||
+ camera_intrinsics->image_height() != image_height)
+ {
+ camera_intrinsics->SetImageSize(image_width, image_height);
+ }
}
-void libmv_CameraIntrinsicsExtract(struct libmv_CameraIntrinsics *libmvIntrinsics, double *focal_length,
- double *principal_x, double *principal_y, double *k1, double *k2, double *k3, int *width, int *height) {
- libmv::CameraIntrinsics *intrinsics= (libmv::CameraIntrinsics *) libmvIntrinsics;
- *focal_length = intrinsics->focal_length();
- *principal_x = intrinsics->principal_point_x();
- *principal_y = intrinsics->principal_point_y();
- *k1 = intrinsics->k1();
- *k2 = intrinsics->k2();
+void libmv_CameraIntrinsicsExtract(struct libmv_CameraIntrinsics *libmv_intrinsics, double *focal_length,
+ double *principal_x, double *principal_y, double *k1, double *k2, double *k3, int *width, int *height)
+{
+ libmv::CameraIntrinsics *camera_intrinsics = (libmv::CameraIntrinsics *) libmv_intrinsics;
+
+ *focal_length = camera_intrinsics->focal_length();
+ *principal_x = camera_intrinsics->principal_point_x();
+ *principal_y = camera_intrinsics->principal_point_y();
+ *k1 = camera_intrinsics->k1();
+ *k2 = camera_intrinsics->k2();
}
-void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics,
+void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmv_intrinsics,
unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
{
- libmv::CameraIntrinsics *intrinsics = (libmv::CameraIntrinsics *) libmvIntrinsics;
+ libmv::CameraIntrinsics *camera_intrinsics = (libmv::CameraIntrinsics *) libmv_intrinsics;
- intrinsics->Undistort(src, dst, width, height, overscan, channels);
+ camera_intrinsics->Undistort(src, dst, width, height, overscan, channels);
}
void libmv_CameraIntrinsicsUndistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics,
@@ -950,139 +927,32 @@ void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmvIntr
intrinsics->Distort(src, dst, width, height, overscan, channels);
}
-/* ************ distortion ************ */
-
-void libmv_undistortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
-{
- libmv::CameraIntrinsics intrinsics;
-
- intrinsics.SetFocalLength(focal_length, focal_length);
- intrinsics.SetPrincipalPoint(principal_x, principal_y);
- intrinsics.SetRadialDistortion(k1, k2, k3);
-
- intrinsics.Undistort(src, dst, width, height, overscan, channels);
-}
-
-void libmv_undistortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- float *src, float *dst, int width, int height, float overscan, int channels)
-{
- libmv::CameraIntrinsics intrinsics;
-
- intrinsics.SetFocalLength(focal_length, focal_length);
- intrinsics.SetPrincipalPoint(principal_x, principal_y);
- intrinsics.SetRadialDistortion(k1, k2, k3);
-
- intrinsics.Undistort(src, dst, width, height, overscan, channels);
-}
-
-void libmv_distortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels)
-{
- libmv::CameraIntrinsics intrinsics;
-
- intrinsics.SetFocalLength(focal_length, focal_length);
- intrinsics.SetPrincipalPoint(principal_x, principal_y);
- intrinsics.SetRadialDistortion(k1, k2, k3);
-
- intrinsics.Distort(src, dst, width, height, overscan, channels);
-}
-
-void libmv_distortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- float *src, float *dst, int width, int height, float overscan, int channels)
-{
- libmv::CameraIntrinsics intrinsics;
-
- intrinsics.SetFocalLength(focal_length, focal_length);
- intrinsics.SetPrincipalPoint(principal_x, principal_y);
- intrinsics.SetRadialDistortion(k1, k2, k3);
-
- intrinsics.Distort(src, dst, width, height, overscan, channels);
-}
-
/* ************ utils ************ */
-void libmv_applyCameraIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- double x, double y, double *x1, double *y1)
+void libmv_applyCameraIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options,
+ double x, double y, double *x1, double *y1)
{
- libmv::CameraIntrinsics intrinsics;
+ libmv::CameraIntrinsics camera_intrinsics;
- intrinsics.SetFocalLength(focal_length, focal_length);
- intrinsics.SetPrincipalPoint(principal_x, principal_y);
- intrinsics.SetRadialDistortion(k1, k2, k3);
+ cameraIntrinsicsFromOptions(&camera_intrinsics, libmv_camera_intrinsics_options);
- if(focal_length) {
+ if (libmv_camera_intrinsics_options->focal_length) {
/* do a lens undistortion if focal length is non-zero only */
- intrinsics.ApplyIntrinsics(x, y, x1, y1);
+ camera_intrinsics.ApplyIntrinsics(x, y, x1, y1);
}
}
-void libmv_InvertIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- double x, double y, double *x1, double *y1)
+void libmv_InvertIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options,
+ double x, double y, double *x1, double *y1)
{
- libmv::CameraIntrinsics intrinsics;
+ libmv::CameraIntrinsics camera_intrinsics;
- intrinsics.SetFocalLength(focal_length, focal_length);
- intrinsics.SetPrincipalPoint(principal_x, principal_y);
- intrinsics.SetRadialDistortion(k1, k2, k3);
+ cameraIntrinsicsFromOptions(&camera_intrinsics, libmv_camera_intrinsics_options);
- if(focal_length) {
+ if (libmv_camera_intrinsics_options->focal_length) {
/* do a lens distortion if focal length is non-zero only */
- intrinsics.InvertIntrinsics(x, y, x1, y1);
+ camera_intrinsics.InvertIntrinsics(x, y, x1, y1);
}
}
-
-/* ************ point clouds ************ */
-
-static void libmvTransformToMat4(libmv::Mat3 &R, libmv::Vec3 &S, libmv::Vec3 &t, double M[4][4])
-{
- for (int j = 0; j < 3; ++j)
- for (int k = 0; k < 3; ++k)
- M[j][k] = R(k, j) * S(j);
-
- for (int i = 0; i < 3; ++i) {
- M[3][0] = t(0);
- M[3][1] = t(1);
- M[3][2] = t(2);
-
- M[0][3] = M[1][3] = M[2][3] = 0;
- }
-
- M[3][3] = 1.0;
-}
-
-void libmv_rigidRegistration(float (*reference_points)[3], float (*points)[3], int total_points,
- int use_scale, int use_translation, double M[4][4])
-{
- libmv::Mat3 R;
- libmv::Vec3 S;
- libmv::Vec3 t;
- libmv::vector<libmv::Vec3> reference_points_vector, points_vector;
-
- for (int i = 0; i < total_points; i++) {
- reference_points_vector.push_back(libmv::Vec3(reference_points[i][0],
- reference_points[i][1],
- reference_points[i][2]));
-
- points_vector.push_back(libmv::Vec3(points[i][0],
- points[i][1],
- points[i][2]));
- }
-
- if (use_scale && use_translation) {
- libmv::RigidRegistration(reference_points_vector, points_vector, R, S, t);
- }
- else if (use_translation) {
- S = libmv::Vec3(1.0, 1.0, 1.0);
- libmv::RigidRegistration(reference_points_vector, points_vector, R, t);
- }
- else {
- S = libmv::Vec3(1.0, 1.0, 1.0);
- t = libmv::Vec3::Zero();
- libmv::RigidRegistration(reference_points_vector, points_vector, R);
- }
-
- libmvTransformToMat4(R, S, t, M);
-}
diff --git a/extern/libmv/libmv-capi.h b/extern/libmv/libmv-capi.h
index e5885e7addf..c90322c56c5 100644
--- a/extern/libmv/libmv-capi.h
+++ b/extern/libmv/libmv-capi.h
@@ -31,7 +31,6 @@
extern "C" {
#endif
-struct libmv_RegionTracker;
struct libmv_Tracks;
struct libmv_Reconstruction;
struct libmv_Features;
@@ -42,14 +41,6 @@ void libmv_initLogging(const char *argv0);
void libmv_startDebugLogging(void);
void libmv_setLoggingVerbosity(int verbosity);
-/* RegionTracker */
-struct libmv_RegionTracker *libmv_pyramidRegionTrackerNew(int max_iterations, int pyramid_level, int half_window_size, double minimum_correlation);
-struct libmv_RegionTracker *libmv_hybridRegionTrackerNew(int max_iterations, int half_window_size, double minimum_correlation);
-struct libmv_RegionTracker *libmv_bruteRegionTrackerNew(int half_window_size, double minimum_correlation);
-int libmv_regionTrackerTrack(struct libmv_RegionTracker *libmv_tracker, const float *ima1, const float *ima2,
- int width, int height, double x1, double y1, double *x2, double *y2);
-void libmv_regionTrackerDestroy(struct libmv_RegionTracker *libmv_tracker);
-
/* TrackRegion (new planar tracker) */
struct libmv_trackRegionOptions {
int motion_model;
@@ -86,28 +77,42 @@ void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track,
void libmv_tracksDestroy(struct libmv_Tracks *libmv_tracks);
/* Reconstruction solver */
-#define LIBMV_REFINE_FOCAL_LENGTH (1<<0)
-#define LIBMV_REFINE_PRINCIPAL_POINT (1<<1)
-#define LIBMV_REFINE_RADIAL_DISTORTION_K1 (1<<2)
-#define LIBMV_REFINE_RADIAL_DISTORTION_K2 (1<<4)
-/* TODO: make keyframes/distortion model a part of options? */
-struct libmv_reconstructionOptions {
+#define LIBMV_REFINE_FOCAL_LENGTH (1 << 0)
+#define LIBMV_REFINE_PRINCIPAL_POINT (1 << 1)
+#define LIBMV_REFINE_RADIAL_DISTORTION_K1 (1 << 2)
+#define LIBMV_REFINE_RADIAL_DISTORTION_K2 (1 << 4)
+
+typedef struct libmv_cameraIntrinsicsOptions {
+ double focal_length;
+ double principal_point_x, principal_point_y;
+ double k1, k2, k3;
+ double p1, p2;
+ int image_width, image_height;
+} libmv_cameraIntrinsicsOptions;
+
+typedef struct libmv_reconstructionOptions {
+ int keyframe1, keyframe2;
+ int refine_intrinsics;
+
double success_threshold;
int use_fallback_reconstruction;
-};
+} libmv_reconstructionOptions;
typedef void (*reconstruct_progress_update_cb) (void *customdata, double progress, const char *message);
int libmv_refineParametersAreValid(int parameters);
-struct libmv_Reconstruction *libmv_solveReconstruction(struct libmv_Tracks *tracks, int keyframe1, int keyframe2,
- int refine_intrinsics, double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- struct libmv_reconstructionOptions *options, reconstruct_progress_update_cb progress_update_callback,
+struct libmv_Reconstruction *libmv_solveReconstruction(struct libmv_Tracks *libmv_tracks,
+ libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options,
+ libmv_reconstructionOptions *libmv_reconstruction_options,
+ reconstruct_progress_update_cb progress_update_callback,
+ void *callback_customdata);
+struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *libmv_tracks,
+ libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options,
+ libmv_reconstructionOptions *libmv_reconstruction_options,
+ reconstruct_progress_update_cb progress_update_callback,
void *callback_customdata);
-struct libmv_Reconstruction *libmv_solveModal(struct libmv_Tracks *tracks, double focal_length,
- double principal_x, double principal_y, double k1, double k2, double k3,
- reconstruct_progress_update_cb progress_update_callback, void *callback_customdata);
int libmv_reporojectionPointForTrack(struct libmv_Reconstruction *libmv_reconstruction, int track, double pos[3]);
double libmv_reporojectionErrorForTrack(struct libmv_Reconstruction *libmv_reconstruction, int track);
double libmv_reporojectionErrorForImage(struct libmv_Reconstruction *libmv_reconstruction, int image);
@@ -127,52 +132,36 @@ void libmv_destroyFeatures(struct libmv_Features *libmv_features);
/* camera intrinsics */
struct libmv_CameraIntrinsics *libmv_ReconstructionExtractIntrinsics(struct libmv_Reconstruction *libmv_Reconstruction);
-struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(double focal_length, double principal_x, double principal_y,
- double k1, double k2, double k3, int width, int height);
+struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsNew(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options);
-struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsCopy(struct libmv_CameraIntrinsics *libmvIntrinsics);
+struct libmv_CameraIntrinsics *libmv_CameraIntrinsicsCopy(struct libmv_CameraIntrinsics *libmv_intrinsics);
-void libmv_CameraIntrinsicsDestroy(struct libmv_CameraIntrinsics *libmvIntrinsics);
+void libmv_CameraIntrinsicsDestroy(struct libmv_CameraIntrinsics *libmv_intrinsics);
-void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmvIntrinsics, double focal_length,
- double principal_x, double principal_y, double k1, double k2, double k3, int width, int height);
+void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmv_intrinsics,
+ libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options);
-void libmv_CameraIntrinsicsExtract(struct libmv_CameraIntrinsics *libmvIntrinsics, double *focal_length,
+void libmv_CameraIntrinsicsExtract(struct libmv_CameraIntrinsics *libmv_intrinsics, double *focal_length,
double *principal_x, double *principal_y, double *k1, double *k2, double *k3, int *width, int *height);
-void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics,
+void libmv_CameraIntrinsicsUndistortByte(struct libmv_CameraIntrinsics *libmv_intrinsics,
unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels);
-void libmv_CameraIntrinsicsUndistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics,
+void libmv_CameraIntrinsicsUndistortFloat(struct libmv_CameraIntrinsics *libmv_intrinsics,
float *src, float *dst, int width, int height, float overscan, int channels);
-void libmv_CameraIntrinsicsDistortByte(struct libmv_CameraIntrinsics *libmvIntrinsics,
+void libmv_CameraIntrinsicsDistortByte(struct libmv_CameraIntrinsics *libmv_intrinsics,
unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels);
-void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmvIntrinsics,
- float *src, float *dst, int width, int height, float overscan, int channels);
-
-/* dsitortion */
-void libmv_undistortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels);
-void libmv_undistortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- float *src, float *dst, int width, int height, float overscan, int channels);
-
-void libmv_distortByte(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
- unsigned char *src, unsigned char *dst, int width, int height, float overscan, int channels);
-void libmv_distortFloat(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+void libmv_CameraIntrinsicsDistortFloat(struct libmv_CameraIntrinsics *libmv_intrinsics,
float *src, float *dst, int width, int height, float overscan, int channels);
/* utils */
-void libmv_applyCameraIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+void libmv_applyCameraIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options,
double x, double y, double *x1, double *y1);
-void libmv_InvertIntrinsics(double focal_length, double principal_x, double principal_y, double k1, double k2, double k3,
+void libmv_InvertIntrinsics(libmv_cameraIntrinsicsOptions *libmv_camera_intrinsics_options,
double x, double y, double *x1, double *y1);
-/* point clouds */
-void libmv_rigidRegistration(float (*reference_points)[3], float (*points)[3], int total_points,
- int use_scale, int use_translation, double M[4][4]);
-
#ifdef __cplusplus
}
#endif
diff --git a/extern/libmv/libmv/multiview/euclidean_resection.cc b/extern/libmv/libmv/multiview/euclidean_resection.cc
index 2605bf04622..062c8b9067c 100644
--- a/extern/libmv/libmv/multiview/euclidean_resection.cc
+++ b/extern/libmv/libmv/multiview/euclidean_resection.cc
@@ -653,8 +653,8 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera,
// Finally, with all three solutions, select the (R, t) with the best RMSE.
VLOG(2) << "RMSE for solution 0: " << rmse(0);
- VLOG(2) << "RMSE for solution 1: " << rmse(0);
- VLOG(2) << "RMSE for solution 2: " << rmse(0);
+ VLOG(2) << "RMSE for solution 1: " << rmse(1);
+ VLOG(2) << "RMSE for solution 2: " << rmse(2);
size_t n = 0;
if (rmse(1) < rmse(0)) {
n = 1;
diff --git a/extern/libmv/libmv/multiview/fundamental.cc b/extern/libmv/libmv/multiview/fundamental.cc
index 12a611c748f..80f155e804d 100644
--- a/extern/libmv/libmv/multiview/fundamental.cc
+++ b/extern/libmv/libmv/multiview/fundamental.cc
@@ -254,8 +254,8 @@ double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) {
Vec3 Ft_y = F.transpose() * y;
double y_F_x = y.dot(F_x);
- return y_F_x * ( 1 / F_x.head<2>().norm()
- + 1 / Ft_y.head<2>().norm());
+ return Square(y_F_x) * ( 1 / F_x.head<2>().squaredNorm()
+ + 1 / Ft_y.head<2>().squaredNorm());
}
// HZ 9.6 pag 257 (formula 9.12)
diff --git a/extern/libmv/libmv/multiview/homography.cc b/extern/libmv/libmv/multiview/homography.cc
index b5c483998d8..538c62598c0 100644
--- a/extern/libmv/libmv/multiview/homography.cc
+++ b/extern/libmv/libmv/multiview/homography.cc
@@ -264,4 +264,19 @@ bool Homography3DFromCorrespondencesLinear(const Mat &x1,
return false;
}
}
+
+double SymmetricGeometricDistance(Mat3 &H, Vec2 &x1, 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/extern/libmv/libmv/multiview/homography.h
index 786fd3df8ca..a295c4366b6 100644
--- a/extern/libmv/libmv/multiview/homography.h
+++ b/extern/libmv/libmv/multiview/homography.h
@@ -79,6 +79,14 @@ bool Homography3DFromCorrespondencesLinear(const Mat &x1,
Mat4 *H,
double expected_precision =
EigenDouble::dummy_precision());
+
+/**
+ * Calculate symmetric geometric cost:
+ *
+ * D(H * x1, x2)^2 + D(H^-1 * x2, x1)
+ */
+double SymmetricGeometricDistance(Mat3 &H, Vec2 &x1, Vec2 &x2);
+
} // namespace libmv
#endif // LIBMV_MULTIVIEW_HOMOGRAPHY_H_
diff --git a/extern/libmv/libmv/multiview/panography.h b/extern/libmv/libmv/multiview/panography.h
new file mode 100644
index 00000000000..6f01beb0ffd
--- /dev/null
+++ b/extern/libmv/libmv/multiview/panography.h
@@ -0,0 +1,181 @@
+// 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.
+//
+
+#ifndef LIBMV_MULTIVIEW_PANOGRAPHY_H
+#define LIBMV_MULTIVIEW_PANOGRAPHY_H
+
+#include "libmv/numeric/numeric.h"
+#include "libmv/numeric/poly.h"
+#include "libmv/base/vector.h"
+
+namespace libmv {
+
+static bool Build_Minimal2Point_PolynomialFactor(
+ const Mat & x1, const Mat & x2,
+ double * P) //P must be a double[4]
+{
+ assert(2 == x1.rows());
+ assert(2 == x1.cols());
+ assert(x1.rows() == x2.rows());
+ assert(x1.cols() == x2.cols());
+
+ // Setup the variable of the input problem:
+ Vec xx1 = (x1.col(0)).transpose();
+ Vec yx1 = (x1.col(1)).transpose();
+
+ double a12 = xx1.dot(yx1);
+ Vec xx2 = (x2.col(0)).transpose();
+ Vec yx2 = (x2.col(1)).transpose();
+ double b12 = xx2.dot(yx2);
+
+ double a1 = xx1.squaredNorm();
+ double a2 = yx1.squaredNorm();
+
+ double b1 = xx2.squaredNorm();
+ double b2 = yx2.squaredNorm();
+
+ // Build the 3rd degre polynomial in F^2.
+ //
+ // f^6 * p + f^4 * q + f^2* r + s = 0;
+ //
+ // Coefficients in ascending powers of alpha, i.e. P[N]*x^N.
+ // Run panography_coeffs.py to get the below coefficients.
+ P[0] = b1*b2*a12*a12-a1*a2*b12*b12;
+ P[1] = -2*a1*a2*b12+2*a12*b1*b2+b1*a12*a12+b2*a12*a12-a1*b12*b12-a2*b12*b12;
+ P[2] = b1*b2-a1*a2-2*a1*b12-2*a2*b12+2*a12*b1+2*a12*b2+a12*a12-b12*b12;
+ P[3] = b1+b2-2*b12-a1-a2+2*a12;
+
+ // If P[3] equal to 0 we get ill conditionned data
+ return (P[3] != 0.0);
+}
+
+// This implements a minimal solution (2 points) for panoramic stitching:
+//
+// http://www.cs.ubc.ca/~mbrown/minimal/minimal.html
+//
+// [1] M. Brown and R. Hartley and D. Nister. Minimal Solutions for Panoramic
+// Stitching. CVPR07.
+//
+// The 2-point algorithm solves for the rotation of the camera with a single
+// focal length (4 degrees of freedom).
+//
+// Compute from 1 to 3 possible focal lenght for 2 point correspondences.
+// Suppose that the cameras share the same optical center and focal lengths:
+//
+// Image 1 => H*x = x' => Image 2
+// x (u1j) x' (u2j)
+// a (u11) a' (u21)
+// b (u12) b' (u22)
+//
+// The return values are 1 to 3 possible values for the focal lengths such
+// that:
+//
+// [f 0 0]
+// K = [0 f 0]
+// [0 0 1]
+//
+static void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2,
+ vector<double> *fs) {
+
+ // Build Polynomial factor to get squared focal value.
+ double P[4];
+ Build_Minimal2Point_PolynomialFactor(x1, x2, &P[0]);
+
+ // Solve it by using F = f^2 and a Cubic polynomial solver
+ //
+ // F^3 * p + F^2 * q + F^1 * r + s = 0
+ //
+ double roots[3];
+ int num_roots = SolveCubicPolynomial(P, roots);
+ for (int i = 0; i < num_roots; ++i) {
+ if (roots[i] > 0.0) {
+ fs->push_back(sqrt(roots[i]));
+ }
+ }
+}
+
+// Compute the 3x3 rotation matrix that fits two 3D point clouds in the least
+// square sense. The method is from:
+//
+// K. Arun,T. Huand and D. Blostein. Least-squares fitting of 2 3-D point
+// sets. IEEE Transactions on Pattern Analysis and Machine Intelligence,
+// 9:698-700, 1987.
+//
+// Given the calibration matrices K1, K2 solve for the rotation from
+// corresponding image rays.
+//
+// R = min || X2 - R * x1 ||.
+//
+// In case of panography, which is for a camera that shares the same camera
+// center,
+//
+// H = K2 * R * K1.inverse();
+//
+// For the full explanation, see Section 8, Solving for Rotation from [1].
+//
+// Parameters:
+//
+// x1 : Point cloud A (3D coords)
+// x2 : Point cloud B (3D coords)
+//
+// [f 0 0]
+// K1 = [0 f 0]
+// [0 0 1]
+//
+// K2 (the same form as K1, but may have different f)
+//
+// Returns: A rotation matrix that minimizes
+//
+// R = arg min || X2 - R * x1 ||
+//
+static void GetR_FixedCameraCenter(const Mat &x1, const Mat &x2,
+ const double focal,
+ Mat3 *R) {
+ assert(3 == x1.rows());
+ assert(2 <= x1.cols());
+ assert(x1.rows() == x2.rows());
+ assert(x1.cols() == x2.cols());
+
+ // Build simplified K matrix
+ Mat3 K( Mat3::Identity() * 1.0/focal );
+ K(2,2)= 1.0;
+
+ // Build the correlation matrix; equation (22) in [1].
+ Mat3 C = Mat3::Zero();
+ for(int i = 0; i < x1.cols(); ++i) {
+ Mat r1i = (K * x1.col(i)).normalized();
+ Mat r2i = (K * x2.col(i)).normalized();
+ C += r2i * r1i.transpose();
+ }
+
+ // Solve for rotation. Equations (24) and (25) in [1].
+ Eigen::JacobiSVD<Mat> svd(C, Eigen::ComputeThinU | Eigen::ComputeThinV);
+ Mat3 scale = Mat3::Identity();
+ scale(2,2) = ((svd.matrixU() * svd.matrixV().transpose()).determinant() > 0.0)
+ ? 1.0
+ : -1.0;
+
+ (*R) = svd.matrixU() * scale * svd.matrixV().transpose();
+}
+
+} // namespace libmv
+
+#endif // LIBMV_MULTIVIEW_PANOGRAPHY_H
diff --git a/extern/libmv/libmv/simple_pipeline/bundle.cc b/extern/libmv/libmv/simple_pipeline/bundle.cc
index d382cd5a4fc..3e36a78c9df 100644
--- a/extern/libmv/libmv/simple_pipeline/bundle.cc
+++ b/extern/libmv/libmv/simple_pipeline/bundle.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 libmv authors.
+// Copyright (c) 2011, 2012, 2013 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
@@ -18,10 +18,11 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
-#define V3DLIB_ENABLE_SUITESPARSE 1
-
#include <map>
+#include "ceres/ceres.h"
+#include "ceres/rotation.h"
+#include "libmv/base/scoped_ptr.h"
#include "libmv/base/vector.h"
#include "libmv/logging/logging.h"
#include "libmv/multiview/fundamental.h"
@@ -31,218 +32,340 @@
#include "libmv/simple_pipeline/bundle.h"
#include "libmv/simple_pipeline/reconstruction.h"
#include "libmv/simple_pipeline/tracks.h"
-#include "third_party/ssba/Geometry/v3d_cameramatrix.h"
-#include "third_party/ssba/Geometry/v3d_metricbundle.h"
-#include "third_party/ssba/Math/v3d_linear.h"
-#include "third_party/ssba/Math/v3d_linear_utils.h"
+
+#ifdef _OPENMP
+# include <omp.h>
+#endif
namespace libmv {
-void EuclideanBundle(const Tracks &tracks,
- EuclideanReconstruction *reconstruction) {
- CameraIntrinsics intrinsics;
- EuclideanBundleCommonIntrinsics(tracks,
- BUNDLE_NO_INTRINSICS,
- reconstruction,
- &intrinsics);
-}
+// The intrinsics need to get combined into a single parameter block; use these
+// enums to index instead of numeric constants.
+enum {
+ OFFSET_FOCAL_LENGTH,
+ OFFSET_PRINCIPAL_POINT_X,
+ OFFSET_PRINCIPAL_POINT_Y,
+ OFFSET_K1,
+ OFFSET_K2,
+ OFFSET_K3,
+ OFFSET_P1,
+ OFFSET_P2,
+};
-void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
- int bundle_intrinsics,
- EuclideanReconstruction *reconstruction,
- CameraIntrinsics *intrinsics) {
- LG << "Original intrinsics: " << *intrinsics;
- vector<Marker> markers = tracks.AllMarkers();
+namespace {
- // "index" in this context is the index that V3D's optimizer will see. The
- // V3D index must be dense in that the cameras are numbered 0...n-1, which is
- // not the case for the "image" numbering that arises from the tracks
- // structure. The complicated mapping is necessary to convert between the two
- // representations.
- std::map<EuclideanCamera *, int> camera_to_index;
- std::map<EuclideanPoint *, int> point_to_index;
- vector<EuclideanCamera *> index_to_camera;
- vector<EuclideanPoint *> index_to_point;
- int num_cameras = 0;
- int num_points = 0;
- for (int i = 0; i < markers.size(); ++i) {
- const Marker &marker = markers[i];
- EuclideanCamera *camera = reconstruction->CameraForImage(marker.image);
- EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
- if (camera && point) {
- if (camera_to_index.find(camera) == camera_to_index.end()) {
- camera_to_index[camera] = num_cameras;
- index_to_camera.push_back(camera);
- num_cameras++;
- }
- if (point_to_index.find(point) == point_to_index.end()) {
- point_to_index[point] = num_points;
- index_to_point.push_back(point);
- num_points++;
- }
- }
- }
+struct OpenCVReprojectionError {
+ OpenCVReprojectionError(double observed_x, double observed_y)
+ : observed_x(observed_x), observed_y(observed_y) {}
- // Convert libmv's K matrix to V3d's K matrix.
- V3D::Matrix3x3d v3d_K;
- for (int i = 0; i < 3; ++i) {
- for (int j = 0; j < 3; ++j) {
- v3d_K[i][j] = intrinsics->K()(i, j);
+ template <typename T>
+ bool operator()(const T* const intrinsics,
+ const T* const R, // Rotation 3x3 column-major.
+ const T* const t, // Translation 3x1.
+ const T* const X, // Point coordinates 3x1.
+ T* residuals) const {
+ // Unpack the intrinsics.
+ const T& focal_length = intrinsics[OFFSET_FOCAL_LENGTH];
+ const T& principal_point_x = intrinsics[OFFSET_PRINCIPAL_POINT_X];
+ const T& principal_point_y = intrinsics[OFFSET_PRINCIPAL_POINT_Y];
+ const T& k1 = intrinsics[OFFSET_K1];
+ const T& k2 = intrinsics[OFFSET_K2];
+ const T& k3 = intrinsics[OFFSET_K3];
+ const T& p1 = intrinsics[OFFSET_P1];
+ const T& p2 = intrinsics[OFFSET_P2];
+
+ // Compute projective coordinates: x = RX + t.
+ T x[3];
+ x[0] = R[0]*X[0] + R[3]*X[1] + R[6]*X[2] + t[0];
+ x[1] = R[1]*X[0] + R[4]*X[1] + R[7]*X[2] + t[1];
+ x[2] = R[2]*X[0] + R[5]*X[1] + R[8]*X[2] + t[2];
+
+ // Compute normalized coordinates: x /= x[2].
+ T xn = x[0] / x[2];
+ T yn = x[1] / x[2];
+
+ T predicted_x, predicted_y;
+
+ // EuclideanBundle uses empty intrinsics, which breaks undistortion code;
+ // so use an implied focal length of 1.0 if the focal length is exactly
+ // zero.
+ // TODO(keir): Figure out a better way to do this.
+ if (focal_length != T(0)) {
+ // Apply distortion to the normalized points to get (xd, yd).
+ // TODO(keir): Do early bailouts for zero distortion; these are expensive
+ // jet operations.
+
+ ApplyRadialDistortionCameraIntrinsics(focal_length,
+ focal_length,
+ principal_point_x,
+ principal_point_y,
+ k1, k2, k3,
+ p1, p2,
+ xn, yn,
+ &predicted_x,
+ &predicted_y);
+ } else {
+ predicted_x = xn;
+ predicted_y = yn;
}
+
+ // The error is the difference between the predicted and observed position.
+ residuals[0] = predicted_x - T(observed_x);
+ residuals[1] = predicted_y - T(observed_y);
+
+ return true;
}
- // Convert libmv's distortion to v3d distortion.
- V3D::StdDistortionFunction v3d_distortion;
- v3d_distortion.k1 = intrinsics->k1();
- v3d_distortion.k2 = intrinsics->k2();
- v3d_distortion.p1 = intrinsics->p1();
- v3d_distortion.p2 = intrinsics->p2();
-
- // Convert libmv's cameras to V3D's cameras.
- std::vector<V3D::CameraMatrix> v3d_cameras(index_to_camera.size());
- for (int k = 0; k < index_to_camera.size(); ++k) {
- V3D::Matrix3x3d R;
- V3D::Vector3d t;
-
- // Libmv's rotation matrix type.
- const Mat3 &R_libmv = index_to_camera[k]->R;
- const Vec3 &t_libmv = index_to_camera[k]->t;
-
- for (int i = 0; i < 3; ++i) {
- for (int j = 0; j < 3; ++j) {
- R[i][j] = R_libmv(i, j);
- }
- t[i] = t_libmv(i);
- }
- v3d_cameras[k].setIntrinsic(v3d_K);
- v3d_cameras[k].setRotation(R);
- v3d_cameras[k].setTranslation(t);
+ double observed_x;
+ double observed_y;
+};
+
+// TODO(keir): Get rid of the parameterization! Ceres will work much faster if
+// the rotation block is angle-axis and also the translation is merged into a
+// single parameter block.
+struct RotationMatrixPlus {
+ template<typename T>
+ bool operator()(const T* R_array, // Rotation 3x3 col-major.
+ const T* delta, // Angle-axis delta
+ T* R_plus_delta_array) const {
+ T angle_axis[3];
+
+ ceres::RotationMatrixToAngleAxis(R_array, angle_axis);
+
+ angle_axis[0] += delta[0];
+ angle_axis[1] += delta[1];
+ angle_axis[2] += delta[2];
+
+ ceres::AngleAxisToRotationMatrix(angle_axis, R_plus_delta_array);
+
+ return true;
}
- LG << "Number of cameras: " << index_to_camera.size();
-
- // Convert libmv's points to V3D's points.
- std::vector<V3D::Vector3d> v3d_points(index_to_point.size());
- for (int i = 0; i < index_to_point.size(); i++) {
- v3d_points[i][0] = index_to_point[i]->X(0);
- v3d_points[i][1] = index_to_point[i]->X(1);
- v3d_points[i][2] = index_to_point[i]->X(2);
+};
+
+// TODO(sergey): would be nice to have this in Ceres upstream
+template<typename PlusFunctor, int kGlobalSize, int kLocalSize>
+class AutodiffParameterization : public ceres::LocalParameterization {
+ public:
+ AutodiffParameterization(const PlusFunctor &plus_functor)
+ : plus_functor_(plus_functor) {}
+
+ virtual ~AutodiffParameterization() {}
+
+ virtual bool Plus(const double* x,
+ const double* delta,
+ double* x_plus_delta) const {
+ return plus_functor_(x, delta, x_plus_delta);
}
- LG << "Number of points: " << index_to_point.size();
- // Convert libmv's measurements to v3d measurements.
- int num_residuals = 0;
- std::vector<V3D::Vector2d> v3d_measurements;
- std::vector<int> v3d_camera_for_measurement;
- std::vector<int> v3d_point_for_measurement;
- for (int i = 0; i < markers.size(); ++i) {
- EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image);
- EuclideanPoint *point = reconstruction->PointForTrack(markers[i].track);
- if (!camera || !point) {
- continue;
- }
- V3D::Vector2d v3d_point;
- v3d_point[0] = markers[i].x;
- v3d_point[1] = markers[i].y;
- v3d_measurements.push_back(v3d_point);
- v3d_camera_for_measurement.push_back(camera_to_index[camera]);
- v3d_point_for_measurement.push_back(point_to_index[point]);
- num_residuals++;
+ virtual bool ComputeJacobian(const double* x, double* jacobian) const {
+ double zero_delta[kLocalSize] = { 0.0 };
+ double x_plus_delta[kGlobalSize];
+ const double* parameters[2] = { x, zero_delta };
+ double* jacobians_array[2] = { NULL, jacobian };
+
+ Plus(x, zero_delta, x_plus_delta);
+
+ return ceres::internal::AutoDiff<PlusFunctor,
+ double,
+ kGlobalSize, kLocalSize>
+ ::Differentiate(plus_functor_,
+ parameters,
+ kGlobalSize,
+ x_plus_delta,
+ jacobians_array);
+
+ return true;
}
- LG << "Number of residuals: " << num_residuals;
-
- // Convert from libmv's specification for which intrinsics to bundle to V3D's.
- int v3d_bundle_intrinsics;
+
+ virtual int GlobalSize() const { return kGlobalSize; }
+ virtual int LocalSize() const { return kLocalSize; }
+
+ private:
+ const PlusFunctor &plus_functor_;
+};
+
+void BundleIntrinsicsLogMessage(int bundle_intrinsics) {
if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) {
LG << "Bundling only camera positions.";
- v3d_bundle_intrinsics = V3D::FULL_BUNDLE_METRIC;
} else if (bundle_intrinsics == BUNDLE_FOCAL_LENGTH) {
LG << "Bundling f.";
- v3d_bundle_intrinsics = V3D::FULL_BUNDLE_FOCAL_LENGTH;
} else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH |
BUNDLE_PRINCIPAL_POINT)) {
LG << "Bundling f, px, py.";
- v3d_bundle_intrinsics = V3D::FULL_BUNDLE_FOCAL_LENGTH_PP;
} else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH |
BUNDLE_PRINCIPAL_POINT |
BUNDLE_RADIAL)) {
LG << "Bundling f, px, py, k1, k2.";
- v3d_bundle_intrinsics = V3D::FULL_BUNDLE_RADIAL;
} else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH |
BUNDLE_PRINCIPAL_POINT |
BUNDLE_RADIAL |
BUNDLE_TANGENTIAL)) {
LG << "Bundling f, px, py, k1, k2, p1, p2.";
- v3d_bundle_intrinsics = V3D::FULL_BUNDLE_RADIAL_TANGENTIAL;
} else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH |
BUNDLE_RADIAL |
BUNDLE_TANGENTIAL)) {
LG << "Bundling f, px, py, k1, k2, p1, p2.";
- v3d_bundle_intrinsics = V3D::FULL_BUNDLE_RADIAL_TANGENTIAL;
} else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH |
BUNDLE_RADIAL)) {
LG << "Bundling f, k1, k2.";
- v3d_bundle_intrinsics = V3D::FULL_BUNDLE_FOCAL_AND_RADIAL;
} else if (bundle_intrinsics == (BUNDLE_FOCAL_LENGTH |
BUNDLE_RADIAL_K1)) {
LG << "Bundling f, k1.";
- v3d_bundle_intrinsics = V3D::FULL_BUNDLE_FOCAL_AND_RADIAL_K1;
+ } else if (bundle_intrinsics == (BUNDLE_RADIAL_K1 |
+ BUNDLE_RADIAL_K2)) {
+ LG << "Bundling k1, k2.";
} else {
LOG(FATAL) << "Unsupported bundle combination.";
}
+}
- // Ignore any outliers; assume supervised tracking.
- double v3d_inlier_threshold = 500000.0;
-
- // Finally, run the bundle adjustment.
- V3D::CommonInternalsMetricBundleOptimizer opt(v3d_bundle_intrinsics,
- v3d_inlier_threshold,
- v3d_K,
- v3d_distortion,
- v3d_cameras,
- v3d_points,
- v3d_measurements,
- v3d_camera_for_measurement,
- v3d_point_for_measurement);
- opt.maxIterations = 500;
- opt.minimize();
- if (opt.status == V3D::LEVENBERG_OPTIMIZER_TIMEOUT) {
- LG << "Bundle status: Timed out.";
- } else if (opt.status == V3D::LEVENBERG_OPTIMIZER_SMALL_UPDATE) {
- LG << "Bundle status: Small update.";
- } else if (opt.status == V3D::LEVENBERG_OPTIMIZER_CONVERGED) {
- LG << "Bundle status: Converged.";
- }
+} // namespace
- // Convert V3D's K matrix back to libmv's K matrix.
- Mat3 K;
- for (int i = 0; i < 3; ++i) {
- for (int j = 0; j < 3; ++j) {
- K(i, j) = v3d_K[i][j];
+void EuclideanBundle(const Tracks &tracks,
+ EuclideanReconstruction *reconstruction) {
+ CameraIntrinsics intrinsics;
+ EuclideanBundleCommonIntrinsics(tracks,
+ BUNDLE_NO_INTRINSICS,
+ reconstruction,
+ &intrinsics);
+}
+
+void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
+ int bundle_intrinsics,
+ EuclideanReconstruction *reconstruction,
+ CameraIntrinsics *intrinsics,
+ int bundle_constraints) {
+ LG << "Original intrinsics: " << *intrinsics;
+ vector<Marker> markers = tracks.AllMarkers();
+
+ ceres::Problem::Options problem_options;
+ problem_options.local_parameterization_ownership =
+ ceres::DO_NOT_TAKE_OWNERSHIP;
+
+ ceres::Problem problem(problem_options);
+
+ // Residual blocks with 10 parameters are unwieldly with Ceres, so pack the
+ // intrinsics into a single block and rely on local parameterizations to
+ // control which intrinsics are allowed to vary.
+ double ceres_intrinsics[8];
+ ceres_intrinsics[OFFSET_FOCAL_LENGTH] = intrinsics->focal_length();
+ ceres_intrinsics[OFFSET_PRINCIPAL_POINT_X] = intrinsics->principal_point_x();
+ ceres_intrinsics[OFFSET_PRINCIPAL_POINT_Y] = intrinsics->principal_point_y();
+ ceres_intrinsics[OFFSET_K1] = intrinsics->k1();
+ ceres_intrinsics[OFFSET_K2] = intrinsics->k2();
+ ceres_intrinsics[OFFSET_K3] = intrinsics->k3();
+ ceres_intrinsics[OFFSET_P1] = intrinsics->p1();
+ ceres_intrinsics[OFFSET_P2] = intrinsics->p2();
+
+ RotationMatrixPlus rotation_matrix_plus;
+ AutodiffParameterization<RotationMatrixPlus, 9, 3>
+ rotation_parameterization(rotation_matrix_plus);
+
+ int num_residuals = 0;
+ for (int i = 0; i < markers.size(); ++i) {
+ const Marker &marker = markers[i];
+ EuclideanCamera *camera = reconstruction->CameraForImage(marker.image);
+ EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
+ if (!camera || !point) {
+ continue;
}
- }
- intrinsics->SetK(K);
-
- // Convert V3D's distortion back to libmv's distortion.
- intrinsics->SetRadialDistortion(v3d_distortion.k1, v3d_distortion.k2, 0.0);
- intrinsics->SetTangentialDistortion(v3d_distortion.p1, v3d_distortion.p2);
-
- // Convert V3D's cameras back to libmv's cameras.
- for (int k = 0; k < num_cameras; k++) {
- V3D::Matrix3x4d const Rt = v3d_cameras[k].getOrientation();
- for (int i = 0; i < 3; ++i) {
- for (int j = 0; j < 3; ++j) {
- index_to_camera[k]->R(i, j) = Rt[i][j];
- }
- index_to_camera[k]->t(i) = Rt[i][3];
+
+ problem.AddResidualBlock(new ceres::AutoDiffCostFunction<
+ OpenCVReprojectionError, 2, 8, 9, 3, 3>(
+ new OpenCVReprojectionError(
+ marker.x,
+ marker.y)),
+ NULL,
+ ceres_intrinsics,
+ &camera->R(0, 0),
+ &camera->t(0),
+ &point->X(0));
+
+ // It's fine if the parameterization for one camera is set repeatedly.
+ problem.SetParameterization(&camera->R(0, 0),
+ &rotation_parameterization);
+
+ if (bundle_constraints & BUNDLE_NO_TRANSLATION) {
+ problem.SetParameterBlockConstant(&camera->t(0));
}
+
+ num_residuals++;
}
+ LG << "Number of residuals: " << num_residuals;
+
+ if(!num_residuals) {
+ LG << "Skipping running minimizer with zero residuals";
+ return;
+ }
+
+ BundleIntrinsicsLogMessage(bundle_intrinsics);
+
+ scoped_ptr<ceres::SubsetParameterization>
+ subset_parameterization(NULL);
+
+ if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) {
+ // No camera intrinsics are refining,
+ // set the whole parameter block as constant for best performance
+ problem.SetParameterBlockConstant(ceres_intrinsics);
+ } else {
+ // Set intrinsics not being bundles as constant
- // Convert V3D's points back to libmv's points.
- for (int k = 0; k < num_points; k++) {
- for (int i = 0; i < 3; ++i) {
- index_to_point[k]->X(i) = v3d_points[k][i];
+ std::vector<int> constant_intrinsics;
+#define MAYBE_SET_CONSTANT(bundle_enum, offset) \
+ if (!(bundle_intrinsics & bundle_enum)) { \
+ constant_intrinsics.push_back(offset); \
}
+ MAYBE_SET_CONSTANT(BUNDLE_FOCAL_LENGTH, OFFSET_FOCAL_LENGTH);
+ MAYBE_SET_CONSTANT(BUNDLE_PRINCIPAL_POINT, OFFSET_PRINCIPAL_POINT_X);
+ MAYBE_SET_CONSTANT(BUNDLE_PRINCIPAL_POINT, OFFSET_PRINCIPAL_POINT_Y);
+ MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K1, OFFSET_K1);
+ MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K2, OFFSET_K2);
+ MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P1, OFFSET_P1);
+ MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P2, OFFSET_P2);
+#undef MAYBE_SET_CONSTANT
+
+ // Always set K3 constant, it's not used at the moment.
+ constant_intrinsics.push_back(OFFSET_K3);
+
+ subset_parameterization.reset(
+ new ceres::SubsetParameterization(8, constant_intrinsics));
+
+ problem.SetParameterization(ceres_intrinsics, subset_parameterization.get());
}
+
+ ceres::Solver::Options options;
+ options.use_nonmonotonic_steps = true;
+ options.preconditioner_type = ceres::SCHUR_JACOBI;
+ options.linear_solver_type = ceres::ITERATIVE_SCHUR;
+ options.use_inner_iterations = true;
+ options.max_num_iterations = 100;
+
+#ifdef _OPENMP
+ options.num_threads = omp_get_max_threads();
+ options.num_linear_solver_threads = omp_get_max_threads();
+#endif
+
+ ceres::Solver::Summary summary;
+ ceres::Solve(options, &problem, &summary);
+
+ LG << "Final report:\n" << summary.FullReport();
+
+ // Copy intrinsics back.
+ if (bundle_intrinsics != BUNDLE_NO_INTRINSICS) {
+ intrinsics->SetFocalLength(ceres_intrinsics[OFFSET_FOCAL_LENGTH],
+ ceres_intrinsics[OFFSET_FOCAL_LENGTH]);
+
+ intrinsics->SetPrincipalPoint(ceres_intrinsics[OFFSET_PRINCIPAL_POINT_X],
+ ceres_intrinsics[OFFSET_PRINCIPAL_POINT_Y]);
+
+ intrinsics->SetRadialDistortion(ceres_intrinsics[OFFSET_K1],
+ ceres_intrinsics[OFFSET_K2],
+ ceres_intrinsics[OFFSET_K3]);
+
+ intrinsics->SetTangentialDistortion(ceres_intrinsics[OFFSET_P1],
+ ceres_intrinsics[OFFSET_P2]);
+ }
+
LG << "Final intrinsics: " << *intrinsics;
}
diff --git a/extern/libmv/libmv/simple_pipeline/bundle.h b/extern/libmv/libmv/simple_pipeline/bundle.h
index 55657cb2d92..573bcf4cc21 100644
--- a/extern/libmv/libmv/simple_pipeline/bundle.h
+++ b/extern/libmv/libmv/simple_pipeline/bundle.h
@@ -67,6 +67,11 @@ void EuclideanBundle(const Tracks &tracks,
BUNDLE_FOCAL_LENGTH | BUNDLE_PRINCIPAL_POINT
BUNDLE_FOCAL_LENGTH | BUNDLE_PRINCIPAL_POINT | BUNDLE_RADIAL
BUNDLE_FOCAL_LENGTH | BUNDLE_PRINCIPAL_POINT | BUNDLE_RADIAL | BUNDLE_TANGENTIAL
+ BUNDLE_RADIAL
+
+ Constraints denotes which blocks to keep constant during bundling.
+ For example it is useful to keep camera translations constant
+ when bundling tripod motions.
\note This assumes an outlier-free set of markers.
@@ -83,10 +88,15 @@ enum BundleIntrinsics {
BUNDLE_TANGENTIAL_P2 = 32,
BUNDLE_TANGENTIAL = 48,
};
+enum BundleConstraints {
+ BUNDLE_NO_CONSTRAINTS = 0,
+ BUNDLE_NO_TRANSLATION = 1,
+};
void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
int bundle_intrinsics,
EuclideanReconstruction *reconstruction,
- CameraIntrinsics *intrinsics);
+ CameraIntrinsics *intrinsics,
+ int bundle_constraints = BUNDLE_NO_CONSTRAINTS);
/*!
Refine camera poses and 3D coordinates using bundle adjustment.
diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
index 6319846a079..658f65c1367 100644
--- a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
+++ b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.cc
@@ -124,20 +124,16 @@ void CameraIntrinsics::ApplyIntrinsics(double normalized_x,
double normalized_y,
double *image_x,
double *image_y) const {
- double x = normalized_x;
- double y = normalized_y;
-
- // Apply distortion to the normalized points to get (xd, yd).
- double r2 = x*x + y*y;
- double r4 = r2 * r2;
- double r6 = r4 * r2;
- double r_coeff = (1 + k1_*r2 + k2_*r4 + k3_*r6);
- double xd = x * r_coeff + 2*p1_*x*y + p2_*(r2 + 2*x*x);
- double yd = y * r_coeff + 2*p2_*x*y + p1_*(r2 + 2*y*y);
-
- // Apply focal length and principal point to get the final image coordinates.
- *image_x = focal_length_x() * xd + principal_point_x();
- *image_y = focal_length_y() * yd + principal_point_y();
+ ApplyRadialDistortionCameraIntrinsics(focal_length_x(),
+ focal_length_y(),
+ principal_point_x(),
+ principal_point_y(),
+ k1(), k2(), k3(),
+ p1(), p2(),
+ normalized_x,
+ normalized_y,
+ image_x,
+ image_y);
}
struct InvertIntrinsicsCostFunction {
diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h
index e0556674ad5..b51b28a4bfb 100644
--- a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h
+++ b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h
@@ -159,6 +159,37 @@ class CameraIntrinsics {
std::ostream& operator <<(std::ostream &os,
const CameraIntrinsics &intrinsics);
+// Apply camera intrinsics to the normalized point to get image coordinates.
+// This applies the radial lens distortion to a point which is in normalized
+// camera coordinates (i.e. the principal point is at (0, 0)) to get image
+// coordinates in pixels. Templated for use with autodifferentiation.
+template <typename T>
+inline void ApplyRadialDistortionCameraIntrinsics(T focal_length_x,
+ T focal_length_y,
+ T principal_point_x,
+ T principal_point_y,
+ T k1, T k2, T k3,
+ T p1, T p2,
+ T normalized_x,
+ T normalized_y,
+ T *image_x,
+ T *image_y) {
+ T x = normalized_x;
+ T y = normalized_y;
+
+ // Apply distortion to the normalized points to get (xd, yd).
+ T r2 = x*x + y*y;
+ T r4 = r2 * r2;
+ T r6 = r4 * r2;
+ T r_coeff = (T(1) + k1*r2 + k2*r4 + k3*r6);
+ T xd = x * r_coeff + T(2)*p1*x*y + p2*(r2 + T(2)*x*x);
+ T yd = y * r_coeff + T(2)*p2*x*y + p1*(r2 + T(2)*y*y);
+
+ // Apply focal length and principal point to get the final image coordinates.
+ *image_x = focal_length_x * xd + principal_point_x;
+ *image_y = focal_length_y * yd + principal_point_y;
+}
+
} // namespace libmv
#endif // LIBMV_SIMPLE_PIPELINE_CAMERA_INTRINSICS_H_
diff --git a/extern/libmv/libmv/simple_pipeline/intersect.cc b/extern/libmv/libmv/simple_pipeline/intersect.cc
index 0c2f744dc1c..660b4b21ece 100644
--- a/extern/libmv/libmv/simple_pipeline/intersect.cc
+++ b/extern/libmv/libmv/simple_pipeline/intersect.cc
@@ -18,6 +18,8 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
+#include "libmv/simple_pipeline/intersect.h"
+
#include "libmv/base/vector.h"
#include "libmv/logging/logging.h"
#include "libmv/multiview/projection.h"
@@ -26,39 +28,41 @@
#include "libmv/multiview/projection.h"
#include "libmv/numeric/numeric.h"
#include "libmv/numeric/levenberg_marquardt.h"
-#include "libmv/simple_pipeline/intersect.h"
#include "libmv/simple_pipeline/reconstruction.h"
#include "libmv/simple_pipeline/tracks.h"
+#include "ceres/ceres.h"
+
namespace libmv {
namespace {
-struct EuclideanIntersectCostFunction {
+class EuclideanIntersectCostFunctor {
public:
- typedef Vec FMatrixType;
- typedef Vec3 XMatrixType;
+ EuclideanIntersectCostFunctor(const Marker &marker,
+ const EuclideanCamera &camera)
+ : marker_(marker), camera_(camera) {}
- EuclideanIntersectCostFunction(const vector<Marker> &markers,
- const EuclideanReconstruction &reconstruction)
- : markers(markers),
- reconstruction(reconstruction) {}
+ template<typename T>
+ bool operator()(const T *X, T *residuals) const {
+ typedef Eigen::Matrix<T, 3, 3> Mat3;
+ typedef Eigen::Matrix<T, 3, 1> Vec3;
- Vec operator()(const Vec3 &X) const {
- Vec residuals(2 * markers.size());
- residuals.setZero();
- for (int i = 0; i < markers.size(); ++i) {
- const EuclideanCamera &camera =
- *reconstruction.CameraForImage(markers[i].image);
- Vec3 projected = camera.R * X + camera.t;
- projected /= projected(2);
- residuals[2*i + 0] = projected(0) - markers[i].x;
- residuals[2*i + 1] = projected(1) - markers[i].y;
- }
- return residuals;
+ Vec3 x(X);
+ Mat3 R(camera_.R.cast<T>());
+ Vec3 t(camera_.t.cast<T>());
+
+ Vec3 projected = R * x + t;
+ projected /= projected(2);
+
+ residuals[0] = projected(0) - T(marker_.x);
+ residuals[1] = projected(1) - T(marker_.y);
+
+ return true;
}
- const vector<Marker> &markers;
- const EuclideanReconstruction &reconstruction;
+
+ const Marker &marker_;
+ const EuclideanCamera &camera_;
};
} // namespace
@@ -95,13 +99,35 @@ bool EuclideanIntersect(const vector<Marker> &markers,
Xp /= Xp(3);
Vec3 X = Xp.head<3>();
- typedef LevenbergMarquardt<EuclideanIntersectCostFunction> Solver;
+ ceres::Problem problem;
- EuclideanIntersectCostFunction triangulate_cost(markers, *reconstruction);
- Solver::SolverParameters params;
- Solver solver(triangulate_cost);
+ for (int i = 0; i < markers.size(); ++i) {
+ const Marker &marker = markers[i];
+ const EuclideanCamera &camera =
+ *reconstruction->CameraForImage(marker.image);
+
+ problem.AddResidualBlock(
+ new ceres::AutoDiffCostFunction<
+ EuclideanIntersectCostFunctor,
+ 2, /* num_residuals */
+ 3>(new EuclideanIntersectCostFunctor(marker, camera)),
+ NULL,
+ &X(0));
+ }
- Solver::Results results = solver.minimize(params, &X);
+ // Configure the solve.
+ ceres::Solver::Options solver_options;
+ solver_options.linear_solver_type = ceres::DENSE_NORMAL_CHOLESKY;
+ solver_options.max_num_iterations = 50;
+ solver_options.update_state_every_iteration = true;
+ solver_options.parameter_tolerance = 1e-16;
+ solver_options.function_tolerance = 1e-16;
+
+ // Run the solve.
+ ceres::Solver::Summary summary;
+ ceres::Solve(solver_options, &problem, &summary);
+
+ VLOG(1) << "Summary:\n" << summary.FullReport();
// Try projecting the point; make sure it's in front of everyone.
for (int i = 0; i < cameras.size(); ++i) {
diff --git a/extern/libmv/libmv/simple_pipeline/modal_solver.cc b/extern/libmv/libmv/simple_pipeline/modal_solver.cc
index bb49b30dbce..169c53bb601 100644
--- a/extern/libmv/libmv/simple_pipeline/modal_solver.cc
+++ b/extern/libmv/libmv/simple_pipeline/modal_solver.cc
@@ -18,11 +18,14 @@
// 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/simple_pipeline/modal_solver.h"
-#include "libmv/simple_pipeline/rigid_registration.h"
+#include "libmv/multiview/panography.h"
#ifdef _MSC_VER
# define snprintf _snprintf
@@ -30,7 +33,8 @@
namespace libmv {
-static void ProjectMarkerOnSphere(Marker &marker, Vec3 &X) {
+namespace {
+void ProjectMarkerOnSphere(Marker &marker, Vec3 &X) {
X(0) = marker.x;
X(1) = marker.y;
X(2) = 1.0;
@@ -38,18 +42,60 @@ static void ProjectMarkerOnSphere(Marker &marker, Vec3 &X) {
X *= 5.0 / X.norm();
}
-static void ModalSolverLogProress(ProgressUpdateCallback *update_callback,
- double progress)
+void ModalSolverLogProress(ProgressUpdateCallback *update_callback,
+ double progress)
{
if (update_callback) {
char message[256];
- snprintf(message, sizeof(message), "Solving progress %d%%", (int)(progress * 100));
+ snprintf(message, sizeof(message), "Solving progress %d%%",
+ (int)(progress * 100));
update_callback->invoke(progress, message);
}
}
+struct ModalReprojectionError {
+ ModalReprojectionError(double observed_x, double observed_y, Vec3 &bundle)
+ : observed_x(observed_x), observed_y(observed_y), 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;
+ Vec3 bundle;
+};
+} // namespace
+
void ModalSolver(Tracks &tracks,
EuclideanReconstruction *reconstruction,
ProgressUpdateCallback *update_callback) {
@@ -59,58 +105,132 @@ void ModalSolver(Tracks &tracks,
LG << "Max image: " << max_image;
LG << "Max track: " << max_track;
- Mat3 R = Mat3::Identity();
+ // 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 frames without doing anything
+ // Skip empty images without doing anything.
if (all_markers.size() == 0) {
- LG << "Skipping frame: " << image;
+ LG << "Skipping image: " << image;
continue;
}
- vector<Vec3> points, reference_points;
+ // 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);
- // Cnstruct pairs of markers from current and previous image,
- // to reproject them and find rigid transformation between
- // previous and current image
- for (int track = 0; track <= max_track; ++track) {
- EuclideanPoint *point = reconstruction->PointForTrack(track);
+ int last_column = x1.cols();
+ x1.conservativeResize(3, last_column + 1);
+ x2.conservativeResize(3, last_column + 1);
- if (point) {
- Marker marker = tracks.MarkerInImageForTrack(image, track);
+ x1.col(last_column) = current_R * point->X;
+ x2.col(last_column) = X;
+ }
+ }
- if (marker.image == image) {
- Vec3 X;
+ if (x1.cols() >= 2) {
+ Mat3 delta_R;
- LG << "Use track " << track << " for rigid registration between image " <<
- image - 1 << " and " << image;
+ // 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);
- ProjectMarkerOnSphere(marker, X);
+ // 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));
- points.push_back(point->X);
- reference_points.push_back(X);
- }
+ 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) {
+ problem.AddResidualBlock(new ceres::AutoDiffCostFunction<
+ ModalReprojectionError,
+ 2, /* num_residuals */
+ 4>(new ModalReprojectionError(marker.x, marker.y,
+ point->X)),
+ NULL,
+ &quaternion(0));
+ num_residuals++;
+
+ problem.SetParameterization(&quaternion(0),
+ quaternion_parameterization);
}
}
- if (points.size()) {
- // Find rigid delta transformation to current image
- RigidRegistration(reference_points, points, R);
+ LG << "Number of residuals: " << num_residuals;
+
+ if (num_residuals) {
+ // Configure the solve.
+ ceres::Solver::Options solver_options;
+ solver_options.linear_solver_type = ceres::DENSE_NORMAL_CHOLESKY;
+ 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());
- // Review if there's new tracks for which position might be reconstructed
+ // 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
+ // New track appeared on this image,
+ // project it's position onto sphere.
LG << "Projecting track " << track << " at image " << image;
diff --git a/extern/libmv/libmv/simple_pipeline/pipeline.cc b/extern/libmv/libmv/simple_pipeline/pipeline.cc
index efceda5c455..463738e42bb 100644
--- a/extern/libmv/libmv/simple_pipeline/pipeline.cc
+++ b/extern/libmv/libmv/simple_pipeline/pipeline.cc
@@ -300,7 +300,7 @@ double InternalReprojectionError(const Tracks &image_tracks,
ex,
ey,
sqrt(ex*ex + ey*ey));
- LG << line;
+ VLOG(1) << line;
total_error += sqrt(ex*ex + ey*ey);
}
diff --git a/extern/libmv/libmv/simple_pipeline/rigid_registration.cc b/extern/libmv/libmv/simple_pipeline/rigid_registration.cc
deleted file mode 100644
index f7cb1e66e7d..00000000000
--- a/extern/libmv/libmv/simple_pipeline/rigid_registration.cc
+++ /dev/null
@@ -1,182 +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/rigid_registration.h"
-#include "libmv/numeric/levenberg_marquardt.h"
-
-namespace libmv {
-
-template<class RigidTransformation>
-struct RigidRegistrationCostFunction {
- public:
- typedef Vec FMatrixType;
- typedef RigidTransformation XMatrixType;
-
- RigidRegistrationCostFunction(const vector<Vec3> &reference_points,
- const vector<Vec3> &points):
- reference_points_(reference_points),
- points_(points) {}
-
- Vec CalculateResiduals(const Mat3 &R,
- const Vec3 &S,
- const Vec3 &t) const {
- Vec residuals(points_.size());
- residuals.setZero();
-
- // Convert scale vector to matrix
- Mat3 SMat = Mat3::Identity();
- SMat(0, 0) *= S(0);
- SMat(1, 1) *= S(1);
- SMat(2, 2) *= S(2);
-
- for (int i = 0; i < points_.size(); i++) {
- Vec3 transformed_point = R * SMat * points_[i] + t;
-
- double norm = (transformed_point - reference_points_[i]).norm();
-
- residuals(i) = norm * norm;
- }
-
- return residuals;
- }
-
- Vec operator()(const Vec9 &RSt) const {
- Mat3 R = RotationFromEulerVector(RSt.head<3>());
- Vec3 S = RSt.segment<3>(3);
- Vec3 t = RSt.tail<3>();
-
- return CalculateResiduals(R, S, t);
- }
-
- Vec operator()(const Vec3 &euler) const {
- Mat3 R = RotationFromEulerVector(euler);
-
- return CalculateResiduals(R, Vec3(1.0, 1.0, 1.0), Vec3::Zero());
- }
-
- Vec operator()(const Vec6 &Rt) const {
- Mat3 R = RotationFromEulerVector(Rt.head<3>());
- Vec3 t = Rt.tail<3>();
-
- return CalculateResiduals(R, Vec3(1.0, 1.0, 1.0), t);
- }
-
- private:
- vector<Vec3> reference_points_;
- vector<Vec3> points_;
-};
-
-static double RigidRegistrationError(const vector<Vec3> &reference_points,
- const vector<Vec3> &points,
- const Mat3 &R,
- const Vec3 &S,
- const Vec3 &t) {
- double error = 0.0;
-
- Mat3 SMat = Mat3::Identity();
- SMat(0, 0) *= S(0);
- SMat(1, 1) *= S(1);
- SMat(2, 2) *= S(2);
-
- for (int i = 0; i < points.size(); i++) {
- Vec3 new_point = R * SMat * points[i] + t;
-
- double norm = (new_point - reference_points[i]).norm();
- error += norm * norm;
- }
- error /= points.size();
-
- return error;
-}
-
-double RigidRegistration(const vector<Vec3> &reference_points,
- const vector<Vec3> &points,
- Mat3 &R,
- Vec3 &S,
- Vec3 &t) {
- typedef LevenbergMarquardt<RigidRegistrationCostFunction <Vec9> > Solver;
-
- RigidRegistrationCostFunction<Vec9> rigidregistration_cost(reference_points, points);
- Solver solver(rigidregistration_cost);
-
- Vec9 RSt = Vec9::Zero();
-
- RSt(3) = RSt(4) = RSt(5) = 1.0;
-
- Solver::SolverParameters params;
- /*Solver::Results results = */ solver.minimize(params, &RSt);
- /* TODO(sergey): better error handling here */
-
- LG << "Rigid registration completed, rotation is:" << RSt.head<3>().transpose()
- << ", scale is " << RSt.segment<3>(3).transpose()
- << ", translation is " << RSt.tail<3>().transpose();
-
- // Decompose individual rotation and translation
- R = RotationFromEulerVector(RSt.head<3>());
- S = RSt.segment<3>(3);
- t = RSt.tail<3>();
-
- return RigidRegistrationError(reference_points, points, R, S, t);
-}
-
-double RigidRegistration(const vector<Vec3> &reference_points,
- const vector<Vec3> &points,
- Mat3 &R,
- Vec3 &t) {
- typedef LevenbergMarquardt<RigidRegistrationCostFunction <Vec6> > Solver;
-
- RigidRegistrationCostFunction<Vec6> rigidregistration_cost(reference_points, points);
- Solver solver(rigidregistration_cost);
-
- Vec6 Rt = Vec6::Zero();
- Solver::SolverParameters params;
- /*Solver::Results results = */solver.minimize(params, &Rt);
- /* TODO(sergey): better error handling here */
-
- LG << "Rigid registration completed, rotation is:" << Rt.head<3>().transpose()
- << ", translation is " << Rt.tail<3>().transpose();
-
- R = RotationFromEulerVector(Rt.head<3>());
- t = Rt.tail<3>();
-
- return RigidRegistrationError(reference_points, points, R, Vec3(1.0, 1.0, 1.0), t);
-}
-
-double RigidRegistration(const vector<Vec3> &reference_points,
- const vector<Vec3> &points,
- Mat3 &R) {
- typedef LevenbergMarquardt<RigidRegistrationCostFunction <Vec3> > Solver;
-
- RigidRegistrationCostFunction<Vec3> rigidregistration_cost(reference_points, points);
- Solver solver(rigidregistration_cost);
-
- Vec3 euler = Vec3::Zero();
- Solver::SolverParameters params;
- /*Solver::Results results = */solver.minimize(params, &euler);
- /* TODO(sergey): better error handling here */
-
- LG << "Rigid registration completed, rotation is:" << euler.transpose();
-
- R = RotationFromEulerVector(euler);
-
- return RigidRegistrationError(reference_points, points, R, Vec3(1.0, 1.0, 1.0), Vec3::Zero());
-}
-
-} // namespace libmv
diff --git a/extern/libmv/libmv/simple_pipeline/rigid_registration.h b/extern/libmv/libmv/simple_pipeline/rigid_registration.h
deleted file mode 100644
index 21ea57af507..00000000000
--- a/extern/libmv/libmv/simple_pipeline/rigid_registration.h
+++ /dev/null
@@ -1,68 +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.
-
-#ifndef LIBMV_SIMPLE_PIPELINE_RIGID_REGISTRATION_H_
-#define LIBMV_SIMPLE_PIPELINE_RIGID_REGISTRATION_H_
-
-#include "libmv/base/vector.h"
-#include "libmv/numeric/numeric.h"
-
-namespace libmv {
-
-/*!
- Searched for an affine transformation of rigid 3D object defined by it's
- vertices positions from it's current state called points to it's desired
- state called reference points.
-
- Returns rotation matrix, per-component scale vector and translation which
- transforms points to the mot close state to reference_points.
-
- Return value is an average squared distance between reference state
- and transformed one.
-
- Minimzation of distance between point pairs is used to register such a
- rigid transformation and algorithm assumes that pairs of points are
- defined by point's index in a vector, so points with the same index
- belongs to the same pair.
- */
-double RigidRegistration(const vector<Vec3> &reference_points,
- const vector<Vec3> &points,
- Mat3 &R,
- Vec3 &S,
- Vec3 &t);
-
-/*!
- * Same as RigidRegistration but provides registration of rotation and translation only
- */
-double RigidRegistration(const vector<Vec3> &reference_points,
- const vector<Vec3> &points,
- Mat3 &R,
- Vec3 &t);
-
-/*!
- * Same as RigidRegistration but provides registration of rotation only
- */
-double RigidRegistration(const vector<Vec3> &reference_points,
- const vector<Vec3> &points,
- Mat3 &R);
-
-} // namespace libmv
-
-#endif // LIBMV_SIMPLE_PIPELINE_RIGID_REGISTRATION_H_
diff --git a/extern/libmv/patches/series b/extern/libmv/patches/series
index 1db7983fdd0..e69de29bb2d 100644
--- a/extern/libmv/patches/series
+++ b/extern/libmv/patches/series
@@ -1 +0,0 @@
-v3d_verbosity.patch
diff --git a/extern/libmv/patches/v3d_verbosity.patch b/extern/libmv/patches/v3d_verbosity.patch
deleted file mode 100644
index f5c6afbd0b5..00000000000
--- a/extern/libmv/patches/v3d_verbosity.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff --git a/src/libmv/simple_pipeline/bundle.cc b/src/libmv/simple_pipeline/bundle.cc
-index fa0b6cc..d382cd5 100644
---- a/src/libmv/simple_pipeline/bundle.cc
-+++ b/src/libmv/simple_pipeline/bundle.cc
-@@ -194,7 +194,6 @@ void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
- double v3d_inlier_threshold = 500000.0;
-
- // Finally, run the bundle adjustment.
-- V3D::optimizerVerbosenessLevel = 1;
- V3D::CommonInternalsMetricBundleOptimizer opt(v3d_bundle_intrinsics,
- v3d_inlier_threshold,
- v3d_K,
diff --git a/extern/libmv/third_party/ceres/CMakeLists.txt b/extern/libmv/third_party/ceres/CMakeLists.txt
index f0c0a4b269f..b71fe1d5cdb 100644
--- a/extern/libmv/third_party/ceres/CMakeLists.txt
+++ b/extern/libmv/third_party/ceres/CMakeLists.txt
@@ -54,6 +54,7 @@ set(SRC
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/cxsparse.cc
internal/ceres/dense_normal_cholesky_solver.cc
@@ -71,11 +72,18 @@ set(SRC
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/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_solver.cc
+ internal/ceres/polynomial.cc
+ internal/ceres/preconditioner.cc
internal/ceres/problem.cc
internal/ceres/problem_impl.cc
internal/ceres/program.cc
@@ -84,7 +92,7 @@ set(SRC
internal/ceres/runtime_numeric_diff_cost_function.cc
internal/ceres/schur_complement_solver.cc
internal/ceres/schur_eliminator.cc
- internal/ceres/schur_ordering.cc
+ internal/ceres/schur_jacobi_preconditioner.cc
internal/ceres/scratch_evaluate_preparer.cc
internal/ceres/solver.cc
internal/ceres/solver_impl.cc
@@ -99,26 +107,34 @@ set(SRC
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/ceres.h
include/ceres/conditioned_cost_function.h
include/ceres/cost_function.h
+ include/ceres/cost_function_to_functor.h
include/ceres/crs_matrix.h
+ include/ceres/dynamic_autodiff_cost_function.h
include/ceres/fpclassify.h
+ include/ceres/gradient_checker.h
include/ceres/internal/autodiff.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/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_functor.h
+ include/ceres/ordered_groups.h
include/ceres/problem.h
include/ceres/rotation.h
include/ceres/sized_cost_function.h
@@ -141,6 +157,7 @@ set(SRC
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/cxsparse.h
internal/ceres/dense_jacobian_writer.h
@@ -150,6 +167,7 @@ set(SRC
internal/ceres/detect_structure.h
internal/ceres/dogleg_strategy.h
internal/ceres/evaluator.h
+ internal/ceres/execution_summary.h
internal/ceres/file.h
internal/ceres/gradient_checking_cost_function.h
internal/ceres/graph_algorithms.h
@@ -161,13 +179,19 @@ set(SRC
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/low_rank_inverse_hessian.h
internal/ceres/map_util.h
internal/ceres/matrix_proto.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/polynomial_solver.h
+ internal/ceres/polynomial.h
+ internal/ceres/preconditioner.h
internal/ceres/problem_impl.h
internal/ceres/program_evaluator.h
internal/ceres/program.h
@@ -178,7 +202,7 @@ set(SRC
internal/ceres/schur_complement_solver.h
internal/ceres/schur_eliminator.h
internal/ceres/schur_eliminator_impl.h
- internal/ceres/schur_ordering.h
+ internal/ceres/schur_jacobi_preconditioner.h
internal/ceres/scratch_evaluate_preparer.h
internal/ceres/solver_impl.h
internal/ceres/sparse_matrix.h
@@ -192,6 +216,7 @@ set(SRC
internal/ceres/trust_region_strategy.h
internal/ceres/visibility_based_preconditioner.h
internal/ceres/visibility.h
+ internal/ceres/wall_time.h
)
#if(FALSE)
@@ -236,8 +261,15 @@ add_definitions(
-DCERES_NO_CXSPARSE
-DCERES_NO_PROTOCOL_BUFFERS
-DCERES_RESTRICT_SCHUR_SPECIALIZATION
+ -DCERES_HAVE_RWLOCK
)
+if(WITH_OPENMP)
+ add_definitions(
+ -DCERES_USE_OPENMP
+ )
+endif()
+
if(MSVC10)
add_definitions(
-D"CERES_HASH_NAMESPACE_START=namespace std {"
diff --git a/extern/libmv/third_party/ceres/ChangeLog b/extern/libmv/third_party/ceres/ChangeLog
index 8b84328cf98..ebfb771be02 100644
--- a/extern/libmv/third_party/ceres/ChangeLog
+++ b/extern/libmv/third_party/ceres/ChangeLog
@@ -1,524 +1,572 @@
-commit 552f9f85bba89f00ca307bc18fbda1dff23bd0e4
+commit d2a5195b512164fec286c6a52b40d7766977caa3
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Aug 31 07:27:22 2012 -0700
+Date: Sun Feb 24 15:09:17 2013 -0800
- Various minor bug fixes to the solver logic.
+ Version history update.
- 1. CostFunction returning false is handled better.
- If only the cost is being evaluated, it is possible to
- use the false value as an infinite value signal/outside
- a region of validity. This allows a weak form of constraint
- handling. Useful for example in handling infinities.
+ Change-Id: I477ec05a78ca4cd735a525253c9b6adfa3bddea7
+
+commit 2160c5b757c44206c6face6ca62d381f1db7a291
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Sun Feb 24 14:15:45 2013 -0800
+
+ Minor release script fixes.
- 2. Changed the way how the slop around zero when model_cost
- is larger than the current cost. Relative instead of absolute
- tolerances are used. The same logic is propagated how the
- corresponding clamping of the model_cost is done.
+ Change-Id: Ifd0a7f4f584c85d4d9574eca46094b372a8d7aff
+
+commit b53c9667f508c125b8aa833e7a063fa44ef8a98e
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Mon Feb 25 01:14:26 2013 +0600
+
+ Solve No Previous Prototype GCC warning
- 3. Fixed a minor indexing bug in nist.cc.
+ In some cases there were missing includes of own
+ header files from implementation files.
- 4. Some minor logging fixes to nist.cc to make it more
- compatible with the rest of ceres.
+ In other cases moved function which are only used
+ within single file into an anonymous namespace.
- Together these changes, take the successful solve count from
- 41/54 to 46/54 and eliminate all NUMERICAL_FAILURE problems.
+ Change-Id: I2c6b411bcfbc521e2a5f21265dc8e009a548b1c8
+
+commit 267ccc45a3e875bf87832a8ad615be690b4926d3
+Author: Sergey Sharybin <sergey.vfx@gmail.com>
+Date: Mon Feb 25 01:04:16 2013 +0600
+
+ Fix for MinGW build on Windows
- Change-Id: If94170ea4731af5b243805c0200963dd31aa94a7
+ GG_LONGLONG and GG_ULONGLONG shall use LL and ULL suffixes,
+ since MinGW is actuall a GCC compiler.
+
+ Solved by checking whether compilation happens with MinGW
+ or not using standard MinGW's __MINGW32__ and __MINGW64__
+ definitions.
+
+ Change-Id: I789b34f6342a56ba42f4b280f7242700022ab7a1
-commit 0b776b5cc9634d3b88d623905b96006f7647ce3e
+commit 509f68cfe3fd13b794c4e67ff38c761407c858cf
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 30 15:26:17 2012 -0700
+Date: Wed Feb 20 01:39:03 2013 -0800
- Update docs.
+ Problem::Evaluate implementation.
+
+ 1. Add Problem::Evaluate and tests.
+ 2. Remove Solver::Summary::initial/final_*
+ 3. Remove Solver::Options::return_* members.
+ 4. Various cpplint cleanups.
- Change-Id: I69d50bcd37aed3bea2190ca614f023e83172901b
+ Change-Id: I4266de53489896f72d9c6798c5efde6748d68a47
-commit 2d7176ad7c8fb7238ca8abd6de73415d95877494
-Author: Petter Strandmark <petter.strandmark@gmail.com>
-Date: Thu Aug 30 19:51:24 2012 -0700
+commit d4a0bf86d688d1b68e00ff302858de5a4e0d9727
+Author: Keir Mierle <mierle@gmail.com>
+Date: Sun Feb 24 10:35:44 2013 -0800
- max_consecutive_nonmonotonic_steps should be int
+ Fix threading build on Windows.
+
+ On Windows, including the "windows.h" header defines an enormous number of
+ symbols; some of which are macros with common names. In particular, "ERROR" and
+ "min" and "max" get defined. This causes clashes when user code references
+ these names in a context other than the intended use in windows.h.
+
+ To deal with this, the Microsoft engineers added the ability to control the
+ definition of these symbols by adding extra defines. In particular, including
+ windows.h in the following way
- Found via Visual Studio warning.
+ #define NOGDI
+ #define NOMINMAX
- Change-Id: Id2cd7de562dfc8cd35df5d5f5220dd2d7350eb2c
+ will reduce the number of macros defined. This way they will not conflict with
+ other uses in Ceres. For example, numeric_limits<double>::max() is impossible
+ to call without defining NOMINMAX.
+
+ Change-Id: I166f5d3bb6dc0e2e4b2ebf800fb19e49206f7874
-commit 1a89bcc94e88933f89b20427a45bc40cdd23c056
+commit beb4505311011130a7e54632137b0fbb5824cc9b
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 30 15:26:17 2012 -0700
+Date: Fri Feb 22 13:37:01 2013 -0800
- Better reporting on the NIST problems.
+ Minor fixes
+
+ Based on William Rucklidge's review, including
+ a nasty bug in parameter block removal.
- Change-Id: I7cf774ec3242c0612dbe52fc233c3fc6cff3f031
+ Change-Id: I3a692e589f600ff560ecae9fa85bb0b76063d403
-commit ea11704857a1e4a735e096896e4d775d83981499
+commit 9a88bd7c4b40e2a1e0cd9b0dc09a3517c467e04e
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 29 18:18:48 2012 -0700
+Date: Tue Feb 19 13:09:12 2013 -0800
- Basic harness for testing NIST problems.
+ Minor bug fixes
- Change-Id: I5baaa24dbf0506ceedf4a9be4ed17c84974d71a1
+ Change-Id: I94e4521adf76a6c77db954c4a8955168e9d37b55
-commit 98bf14d2b95386c2c4a6c29154637943dae4c36c
+commit 956ed7e8f2054623615e6ae3601055d613897f26
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 30 10:26:44 2012 -0700
+Date: Tue Feb 19 07:06:15 2013 -0800
- Miscellaneous fixes.
+ Various minor fixes.
+
+ 1. Unused variable warnings and fixes.
+ 2. Minor documentation update.
- Change-Id: I521e11f2d20bf24960bbc6b5dab4ec8bb1503d23
+ Change-Id: I815588a5806df1030a7c8750f4fb594c503f8998
-commit 1e3cbd9a4442cdd8fda43a7fb452f19dac8c74af
-Author: Petter Strandmark <strandmark@google.com>
-Date: Wed Aug 29 09:39:56 2012 -0700
+commit 3e2c4ef9ad35e94198f4f3367b99fd91e26996a1
+Author: Keir Mierle <mierle@gmail.com>
+Date: Sun Feb 17 12:37:55 2013 -0800
- Caching the symbolic Cholesky factorization when using CXSparse
-
- Average factorization times for bundle adjustment test problem:
- SuiteSparse: 0.2794 s.
- CXSparse: 0.4039 s.
- CXSparse cached: 0.2399 s.
+ Add adapters for column/row-major matrices to rotation.h
- CXSparse will still be slower, though, because it has to compute
- the transpose and J^T * J.
+ This patch introduces a matrix wrapper (MatrixAdapter) that allows to
+ transparently pass pointers to row-major or column-major matrices
+ to the conversion functions.
- Change-Id: If9cdaa3dd520bee84b56e5fd4953b56a93db6bde
+ Change-Id: I7f1683a8722088cffcc542f593ce7eb46fca109b
-commit 8b64140878ccd1e183d3715c38942a81fdecefde
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 29 05:41:22 2012 -0700
+commit 04938efe4bedec112083c5ceb227ba004f96bd01
+Author: Keir Mierle <mierle@gmail.com>
+Date: Sun Feb 17 12:37:55 2013 -0800
- Documentation update
+ Add support for removing parameter and residual blocks.
- Change-Id: I271a0422e7f6f42bcfd1dc6b5dc10c7a18f6a179
-
-commit a5353acd85a9fd19370b3d74035d87b0f0bac230
-Author: Petter Strandmark <petter.strandmark@gmail.com>
-Date: Tue Aug 28 18:16:41 2012 -0700
-
- Adding gflags include to test_util.cc
+ This adds support for removing parameter and residual blocks.
+ There are two modes of operation: in the first, removals of
+ paremeter blocks are expensive, since each remove requires
+ scanning all residual blocks to find ones that depend on the
+ removed parameter. In the other, extra memory is sacrificed to
+ maintain a list of the residuals a parameter block depends on,
+ removing the need to scan. In both cases, removing residual blocks
+ is fast.
- test_util seems to need gflags.
+ As a caveat, any removals destroys the ordering of the parameters,
+ so the residuals or jacobian returned from Solver::Solve() is
+ meaningless. There is some debate on the best way to handle this;
+ the details remain for a future change.
- Change-Id: I0c4757960f8ac69ad599c138aea58e3c88a4ea28
-
-commit 87ca1b2ba28ec512752bbcf5fc994ce1434eb765
-Author: Petter Strandmark <petter.strandmark@gmail.com>
-Date: Tue Aug 28 18:05:20 2012 -0700
-
- Changing random.h to use cstdlib for Windows compability.
+ This also adds some overhead, even in the case that fast removals
+ are not requested:
- As discussed with Sameer today.
+ - 1 int32 to each residual, to track its position in the program.
+ - 1 pointer to each parameter, to store the dependent residuals.
- Change-Id: If3d0284830c6591c71cc77b8400cafb45c0da61f
+ Change-Id: I71dcac8656679329a15ee7fc12c0df07030c12af
-commit aeb00a07323808a0a1816e733ad18a87d5109ea3
-Author: Petter Strandmark <strandmark@google.com>
-Date: Mon Aug 27 22:22:57 2012 -0700
+commit fa21df8cd969bb257b87c9ef7c0147d8d5ea8725
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Feb 18 08:48:52 2013 -0800
- Removing gomp for Visual Studio
+ Add script for building documentation.
+
+ Update make_release
- Linking currently fails in Visual Studio due to a missing library
- "gomp.lib". This is not needed in Visual Studio. OpenMP works
- without it.
+ Minor documentation fixes.
- Change-Id: I39e204a8dd4f1b7425df7d4b222d86a8bb961432
+ Change-Id: I1248ec3f58be66b5929aee6f2aa392c15d53ed83
-commit 6f362464ba99b800494d2f15c27768a342ddaa68
-Author: Markus Moll <markus.moll@esat.kuleuven.be>
-Date: Tue Aug 28 01:03:38 2012 +0200
+commit 290b975d1d4eba44205bbeb0fa6b3ce8a6fa4a0c
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Sun Feb 17 16:50:37 2013 -0800
- Add some tests for DoglegStrategy.
+ Preconditioner refactoring.
- Not necessarily a complete set.
+ 1. Added a Preconditioner interface.
+ 2. SCHUR_JACOBI is now its own class and is independent of
+ SuiteSparse.
- Change-Id: I14eb3a38c6fe976c8212f3934655411b6d1e0aa4
+ Change-Id: Id912ab19cf3736e61d1b90ddaf5bfba33e877ec4
-commit 122cf836a6dc9726489ce2fbecc6143bddc1caaf
+commit d010de543530001fa917501a13ba02879c8ea52f
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Aug 24 16:28:27 2012 -0700
+Date: Fri Feb 15 14:26:56 2013 -0800
- Documentation update.
+ Solver::Summary::FullReport() supports line search now.
- Change-Id: I0a3c5ae4bc981a8f5bdd5a8905f923dc5f09a024
+ Change-Id: Ib08d300198b85d9732cfb5785af4235ca4bd5226
-commit 69081719f73da8de2935774a42d237837a91952a
-Author: Keir Mierle <mierle@gmail.com>
-Date: Mon Aug 27 13:28:56 2012 -0700
+commit fbbea464d1c9575d8224220d3e61f92d93fe9739
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Fri Feb 15 11:25:03 2013 -0800
- Remove unnecessary overload for hash<>
+ Update documentation.
- The overload for pointers in hash tables was applied in normal
- usage of schur_ordering.cc. However, the tests did not include the
- overload since they only included collections_port.h. As a result,
- the routines in schur_ordering.cc were using a different hash
- function than that inside the tests.
-
- The fix is to remove the specialization. If this breaks one of the
- compiler configurations, we will find a workaround at that time.
-
- Change-Id: Idbf60415d5e2aec0c865b514ad0c577d21b91405
+ Change-Id: Idb03741fab9facbbbda85d5a82723f0b4c1c6c60
-commit 1762420b6ed76b1c4d30b913b2cac1927b666534
+commit 8e1f83c4c457fb7238eb342eab744c5570b73c4d
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 22 10:01:31 2012 -0700
+Date: Fri Feb 15 08:35:40 2013 -0800
- Update changelog.
+ Speed up Problem construction and destruction.
- Change-Id: Idf5af69d5a9dbe35f58e30a8afcbfcd29bb7ebfe
+ Change-Id: I3147b0b60eedf40f8453d5a39ff04a572c445a2f
-commit 976ab7aca908309b8282cb40bc080ca859136854
-Author: Keir Mierle <mierle@gmail.com>
-Date: Thu Aug 23 18:21:36 2012 -0700
+commit efb47f39c31f0ef1bb9c015c8c0d114153df6379
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Thu Feb 14 19:44:11 2013 -0800
- Remove Google-era vestigial unit test.
+ Documentation update
- Change-Id: Ia7a295a5c759a17c1675a3055d287d3e40e9e0fe
+ Change-Id: I0fec43bff4fe0ea6cd2d2a8b34dac2330a517da0
-commit 6ad6257de0e2152ac5e77dc003758de45187d6ea
-Author: Keir Mierle <mierle@gmail.com>
-Date: Wed Aug 22 11:10:31 2012 -0700
+commit be418a336cae5672111e0f6989e6d8d6c1fa24a6
+Author: Markus Moll <markus.moll@esat.kuleuven.be>
+Date: Fri Feb 15 17:19:28 2013 +0100
- Add a workaround for an Android NDK compiler bug.
-
- On certain NDK build configurations, one of the innermost
- parts of the Schur eliminator would get compiled
- incorrectly. The compiler changed a -= to a +=.
+ Fix evaluation of initial cost and corresponding test
- The normal Ceres unit tests caught the problem; however,
- since it is not possible to build the tests with the NDK
- (only with the standalone toolchain) this was difficult to
- track down. Finding the issue involved pasting the schur
- eliminator unit test inside of solver_impl.cc and other such
- hacks.
+ Commit f102a68e411d11b4864e17b69a2d781e9c2692ad seems to have introduced
+ a bug in both solver_impl.cc and solver_impl_test.cc
+ solver_impl_test showed 3 errors, where two were due to ceres NOT
+ failing when the test expected that, and one was due to the initial cost
+ being wrong (-1 instead of 0.5)
+ Ceres now does not attempt to evaluate the initial cost if
+ options.return_initial_xxx is not set. It therefore did not fail in
+ the tests.
+ It also seems that the CERES_EVALUATE macro erroneously always sets
+ final_cost, even when called with 'initial' as argument.
- Change-Id: Ie91bb545d74fe39f0c8cbd1a6eb69ee4d8b25fb2
+ Change-Id: Ia3c3eeb476e7023a3f80b201124010d6c67e9824
-commit aecb2dc92b4aa7f3bf77a1ac918e62953602392b
+commit 974513a41ff1ddc671d3dc6aa09ce708bbe447da
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 22 10:08:17 2012 -0700
+Date: Tue Feb 12 14:22:40 2013 -0800
- Fix relative path bug in bibtex call.
+ Bug fix in DynamicAutoDiffCostFunction
+
+ Add handling of constant parameter blocks.
- Change-Id: I0d31786564320a6831259bcdf4c75a6b665c43ad
+ Change-Id: I8b2ea79f47e190604fc4bed27705798240689f71
-commit 1e2892009e591804df6286caebd5c960e7e3b099
-Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Tue Aug 21 18:00:54 2012 -0700
+commit 3130b3cea4028c71d9ae18b7465d7627f29fef7d
+Author: Keir Mierle <mierle@gmail.com>
+Date: Mon Feb 11 19:39:29 2013 -0800
- Update Summary::FullReport to report dogleg type.
+ Add support for dynamic autodiff
- Change-Id: I0b4be8d7486c1c4b36b299693b3fe8b0d3426537
+ Change-Id: I17d573696172ab691a9653db99a620e4bc1bd0d0
-commit 295ade1122a86b83e1ea605d5ca394f315874717
+commit c58e6dc3ea550302c8151003b17e9bc2a1acc316
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Wed Aug 22 06:51:22 2012 -0700
+Date: Mon Feb 11 16:41:06 2013 -0800
- Fix Eigen3 Row/Column Major storage issue.
-
- Eigen3 does not allow column vectors to be stored in row-major
- format. NumericDiffCostFunction by default stores its Jacobian
- matrices in row-major format. This works fine if the residual
- contains more than one variable. But if the residual block
- depends on one variable and has more than one residuals, the
- resulting Jacobian matrix is a column matrix in row-major format
- resulting in a compile time error.
+ More refined event logging in solver_impl.cc
- The fix is to check the template parameters and switch to column-major
- storage as needed.
-
- Thanks to Lena Gieseke for reporting this.
-
- Change-Id: Icc51c5b38e1f3609e0e1ecb3c4e4a02aecd72c3b
+ Change-Id: Ie3061c921c006d2600d16185c690f52ccf816f68
-commit 9ad27e8e9fb1bbd2054e2f6ae37623e01428f1c0
-Author: Arnaud Gelas <arnaudgelas@gmail.com>
-Date: Tue Aug 21 09:56:30 2012 +0200
+commit f102a68e411d11b4864e17b69a2d781e9c2692ad
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Feb 11 15:08:40 2013 -0800
- Add one uninstall target to remove all installed files
+ Remove extraneous initial and final evals.
- Change-Id: Ifcf89a6c27b25f28403d95a50e29c093a525298f
+ Change-Id: I80ed87435f399cbf452c68be7ea1e7139696aa4a
-commit 0c3a748ee49e04fe334f8f5a433649d18003d550
-Author: Markus Moll <markus.moll@esat.kuleuven.be>
-Date: Tue Aug 21 14:44:59 2012 +0200
+commit 0593747ee09e21a9c0a2b604d51e21a6cdd21315
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Feb 11 13:57:12 2013 -0800
- Allow equal lower and upper bound for diagonal scaling.
+ Fix a memory leak in cxsparse.cc
- This way, setting the lower and upper bound both to 1.0, one can disable
- the automatic trust region scaling.
+ Thanks to Alexander Mordvintsev for reporting it.
- Change-Id: Ifa317a6911b813a89c1cf7fdfde25af603705319
+ Change-Id: Ia872be42ce80209e46722fc16a928496cf97e256
-commit 3d644b76adefac6475b91dc53c3ae5e01c4f4d66
-Author: Arnaud Gelas <arnaudgelas@gmail.com>
-Date: Thu Aug 16 17:33:21 2012 +0200
+commit 0abfb8f46f534b05413bb4d64b960d6fd0a9befb
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Feb 11 13:40:04 2013 -0800
- Install headers, libraries and pdf
+ Delete the tex documentation.
- Headers are installed in ${CMAKE_INSTALL_PREFIX}/include/ceres
- Libraries are installed in ${CMAKE_INSTALL_PREFIX}/lib
- pdf is installed in ${CMAKE_INSTALL_PREFIX}/share/ceres/docs
-
- Change-Id: Ic175f2c2f5fa86820a1e8c64c2ed171f4a302a68
+ Change-Id: I15c78a8b33c5fd94941238814ac023a8fb251a20
-commit d2fb5adea4d8c2aeb43c4289c6976798a54d3cf1
-Author: Arnaud Gelas <arnaudgelas@gmail.com>
-Date: Fri Aug 17 10:11:02 2012 +0200
+commit 085cd4a6641c404334d17e5ea38f9e5b68a06ba7
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Wed Feb 6 14:31:07 2013 -0800
- Configure gerrit hook at CMake time
+ Rewrite of the tutorial.
- If the source directory is a clone, at CMake time the commit-msg hook gets
- downloaded and installed in the right location.
+ 1. Quicker starting point.
+ 2. Better discussion of derivatives.
+ 3. Better hyperlinking to code and class documentation.
+ 4. New robust estimation example.
+ 5. Better naming of example code.
+ 6. Removed dependency on gflags in all the core examples covered
+ in the tutorial.
- Change-Id: I5fee17d050ca22d8b92a49fdcc2a1cd6659f209b
+ Change-Id: Ibf3c7fe946fa2b4d22f8916a9366df267d34ca26
-commit 73166098fc4b1072adc30321c666188a3909c43c
-Author: Arnaud Gelas <arnaudgelas@gmail.com>
-Date: Mon Aug 20 15:40:41 2012 +0200
+commit c0fdc9753909fc37fed2cb5e0fcc02fc65789d68
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Wed Feb 6 14:31:07 2013 -0800
- Add one CMake option to build the examples.
+ Update nist.cc to better evaluate results.
- Currently the examples are always built. For external projects, it is useful
- not to compile the examples.
+ Ceres beats Minpack and HBN handily.
- Change-Id: I41d3bde19c7e742818e60f78222d39c43992ca8b
+ Change-Id: I7df8a47b753202ed0b53ab128ce48466bf9f8083
-commit 86d4f1ba41ef14eb1b6b61a7936af83387b35eb2
-Author: Keir Mierle <mierle@gmail.com>
-Date: Mon Aug 20 11:52:04 2012 -0700
+commit d91b671798125fd4889914d92a29cf0f7a5fef21
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Wed Feb 6 01:08:40 2013 -0800
- Add missing return statement.
+ More small changes
+ More small changes to the docs.
- Change-Id: I5eaf718318e27040e3c97e32ee46cf0a11176a37
-
-commit 51eb229da34187a4e8ce73ed9cc0e731998bb2be
-Author: Keir Mierle <mierle@gmail.com>
-Date: Mon Aug 20 11:46:12 2012 -0700
-
- Add Program::ToString() to aid debugging.
+ 1. Better landing page.
+ 2. Minor tweaks to the side bar.
+ 3. Reference to more example code.
+ 4. Local MathJax references.
- Change-Id: I0ab37ed2fe0947ca87a152919d4e7dc9b56dedc6
+ Change-Id: I39b9436dc2803732a875bbbee7f15802c4934031
-commit bcc7100635e2047dc2b77df19a4ded8a6ab4d4b9
-Author: Keir Mierle <mierle@gmail.com>
-Date: Mon Aug 20 11:45:04 2012 -0700
+commit 42a84b87fa5cc34551244a3b2b6a3e1f13a29514
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Fri Feb 1 12:22:53 2013 -0800
- Ignore minted.sty.
+ Expand reporting of timing information.
- Change-Id: I2467a6f801812b9007b51bf14b00757f026e4322
+ 1. Add an ExecutionSummary object to record execution
+ information about Ceres objects.
+ 2. Add an EventLogger object to log events in a function call.
+ 3. Add a ScopedExecutionTimer object to log times in ExecutionSummary.
+ 4. Instrument ProgramEvaluator and all the linear solvers
+ to report their timing statistics.
+ 5. Connect the timing statistics to Summary::FullReport.
+ 6. Add high precision timer on unix systems using
+ gettimeofday() call.
+ 7. Various minor clean ups all around.
+
+ Change-Id: I5e09804b730b09535484124be7dbc1c58eccd1d4
-commit 9705a736dd3d6fbead0d8a6ff77102c69bbcdc08
-Author: Keir Mierle <mierle@gmail.com>
-Date: Mon Aug 20 11:24:05 2012 -0700
+commit 08c891fcb6ea1bf66e6d4619273765a644605dfc
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Feb 4 20:18:58 2013 -0800
- Add ParameterBlock::ToString() to aid debugging.
+ Various small changes.
- Change-Id: Id3f5cb27b855c536dd65a986f345bd8eb2799dfa
+ 1. Compact build instructions.
+ 2. Lots of small edits by Simon Fuhrmann.
+
+ Change-Id: I8c0c67922021041dcf7f4ecdb6c6e6dd2e2fd7e5
-commit 0c714a70e6123ceb68e5cfcd3cfbee0d09deb1db
+commit e2e857ad6be322e9cf750d4b11ccf10800e57d96
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Mon Aug 20 11:18:16 2012 -0700
+Date: Mon Feb 4 19:40:45 2013 -0800
- Fix blanks before private in loss_function.h
+ Sidebar has global table of contents.
- Change-Id: I068bed6431bc7c9b7958af391655df61499000b2
+ Change-Id: I7fe9053868a4660b0db8d7607ee618fc30ddaefd
-commit 51cf7cbe3bac45c6807c2703a2fc3175d76a1b47
-Author: Markus Moll <markus.moll@esat.kuleuven.be>
-Date: Mon Aug 20 20:10:20 2012 +0200
+commit b9182147d96f865673c2756ced4cbb127ca082a3
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Feb 4 17:55:25 2013 -0800
- Add the two-dimensional subspace search to DoglegStrategy
+ Change the theme to be closer to ReadTheDocs.org
- Change-Id: I5163744c100cdf07dd93343d0734ffe0e80364f3
+ Change-Id: I61a76f5b5e5c292b54fdf51b66940ce80bd1cd5f
-commit ad1f7b772e559a911ac3a3b078b0aee1836fe785
+commit 3d87b72c895835bbfc10965d50dc96608632114d
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Mon Aug 20 11:10:34 2012 -0700
+Date: Sat Feb 2 00:49:31 2013 -0800
- Add ArcTanLoss, TolerantLoss and ComposedLossFunction.
+ Convert documentation from LaTeX to Sphinx.
- Based on work by James Roseborough.
+ A live version of the doc can be found at
- Change-Id: Idc4e0b099028f67702bfc7fe3e43dbd96b6f9256
+ http://homes.cs.washington.edu/~sagarwal/ceres-solver/
+
+ As it stands, the documentation has better hyperlinking
+ and coverage than the latex documentation now.
+
+ Change-Id: I7ede3aa83b9b9ef25104caf331e5727b4f5beae5
-commit 05292bf8fc5208b86b4a13544615b584f6efa936
+commit 71c8058478311ff9b3087360827e048dec5dd69a
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Mon Aug 20 07:40:45 2012 -0700
+Date: Thu Jan 31 17:33:01 2013 -0800
- Add a TrustRegionStrategy::Summary object.
+ Remove ExecutionSummary from Evaluator and LinearSolver
- Change-Id: I7caee35a3408ee4a0ec16ba407410d822929340d
+ Change-Id: If4dbaf516a8b14e0a79e1a2116ce66a99ed4a592
-commit b12b906c4d21c3949f0dce62c4c0d083c8edecf1
-Author: Arnaud Gelas <arnaudgelas@gmail.com>
-Date: Wed Aug 15 16:27:38 2012 +0200
+commit fa1c31eee33051d6483bc90fa7b66c3664b23bf3
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Tue Jan 29 17:24:54 2013 -0800
- Add one option to generate the PDF from CMake at build time
+ Correct the documentation for crs_matrix.h
- Make sure pygmentize is installed
+ Thanks to Joydeep Biswas for reporting this.
- Change-Id: I068ba45c33a8e96acc906a464b12d10d58b3e231
+ Change-Id: Iae5fc2274644aab40f2f922a671f65da15ae71fc
-commit b9f15a59361c609ffc4a328aea9be3d265b5da81
+commit bdd87c03ed1cbac62990bf79aa6faed0a132bba9
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Sat Aug 18 13:06:19 2012 -0700
+Date: Tue Jan 29 16:24:31 2013 -0800
- Add a dense Cholesky factorization based linear solver.
+ Add an ExecutionSummary object that the Evaluator and LinearSolver can use to
+ report execution statistics of all kinds.
- For problems with a small number of variables, but a large
- number of residuals, it is sometimes beneficial to use the
- Cholesky factorization on the normal equations, instead of
- the dense QR factorization of the Jacobian, even though it
- is numerically the better thing to do.
+ Currently a single map which maps arbitrary strings to doubles is supported,
+ which allows for precise timing information to be communicated.
- Change-Id: I3506b006195754018deec964e6e190b7e8c9ac8f
+ Change-Id: Ibd930aca5c9e6cae89bcfeffe9b13e2887644881
-commit b3fa009435acf476cd373052e62988f6437970b1
-Author: Arnaud Gelas <arnaudgelas@gmail.com>
-Date: Fri Aug 17 10:31:41 2012 +0200
+commit a2fd9ca8beb5aa11fcc5d2b32e23f161edc93d28
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Tue Jan 29 16:02:41 2013 -0800
- Set CMAKE_*_OUTPUT_DIRECTORY
-
- Gather
- * all executables in ${CMAKE_BINARY_DIR}/bin
- * all libraries (static and dynamic) in ${CMAKE_BINARY_DIR}/lib
+ Fix Android.mk
- Change-Id: Ibc2fa1adfb6f0aea65d66d570259b79546bf3b07
+ Change-Id: I1093c2731283890d1f3792bf8e6741f448f1465d
-commit 1b8a4d5d11671ed83cf6077e363dd95333f08ef8
+commit 977be7cac37316524038fa0168cc5994a5654acd
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Aug 17 16:49:11 2012 -0700
+Date: Sat Jan 26 16:01:54 2013 -0800
- Fix a minor bug in detect_structure logging.
+ Add support for reporting linear solver and inner iteration
+ orderings.
- Change-Id: I117f7745e4c67595b3ff9244cde82b5b5b34ee4b
+ Change-Id: I0588a4285e0925ce689e47bd48ddcc61ce596a1f
-commit 31c1e784ab2cb9294c6e05414cf06aae2b3766de
-Author: Keir Mierle <mierle@gmail.com>
-Date: Fri Aug 17 16:16:32 2012 -0700
+commit 146b9acb4d5570da311fedb5222ad65fe12f233c
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Mon Jan 21 16:16:58 2013 -0800
- Minor cleanups.
+ Update include/ceres.h to export headers.
+ Update the ABI version.
- Change-Id: Ida4866997deeaa1bc2cebd6b69313a05ac82e457
+ Change-Id: I5c1c4f110cddc816bbb5a737634f55b4cbea98e1
-commit e83f7879a8b21c6976e116958caf35bcdcf41cb0
+commit e837aeaf9e63936d745519fa53c726a2ca9d5822
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Aug 17 15:34:42 2012 -0700
+Date: Mon Jan 21 13:05:01 2013 -0800
- Fix SuiteSparse3 UFConfig.h detection really.
+ Documentation update.
- Change-Id: Id187102e755b7d778dff4363f22f9a4697ed12dd
+ Change-Id: Ica8681f4bb58c60349d0dae453c652f2522eebf6
-commit 96f25dc57658d296ee6b6633818b4f1e51d7d587
+commit 2f0d7249ccedac8183e6e5a9cb45ca7c51bb6b41
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Aug 17 15:34:42 2012 -0700
+Date: Fri Jan 18 13:11:32 2013 -0800
- Fix SuiteSparse3 UFConfig.h detection.
+ NumericDiffFunctor.
- Change-Id: Ia59aefdb0ad7f713f76ed79692f2db4fa2821e5b
-
-commit c497bd6cd9aa944f518aa491d3bc645851ff9594
-Author: Markus Moll <markus.moll@esat.kuleuven.be>
-Date: Fri Aug 17 14:40:13 2012 +0200
-
- Add UFconfig and/or SuiteSparse_config test to CMakeLists.txt
+ A wrapper class that takes a variadic functor evaluating a
+ function, numerically differentiates it and makes it available as a
+ templated functor so that it can be easily used as part of Ceres'
+ automatic differentiation framework.
- SuiteSparse 4 requires linking to libsuitesparseconfig.a.
- Both SuiteSparse 3 and SuiteSparse 4 require an additional header
- (either UFconfig.h or SuiteSparse_config.h) that is not found if it is
- in a separate path. Therefore, add explicit checks.
+ The tests for NumericDiffCostFunction and NumericDiffFunctor have
+ a lot of stuff that is common, so refactor them to reduce code.
- Change-Id: I699902b5db4f1b7f17134b5a54f9aa681445e294
+ Change-Id: I83b01e58b05e575fb2530d15cbd611928298646a
-commit 383c04f4236d92801c7c674892814362dedf7ad6
+commit 2fc0ed6143ad499d6dc82d621ff5ec69170beb52
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Fri Aug 17 10:14:04 2012 -0700
+Date: Tue Jan 15 11:34:10 2013 -0800
- Fix QuaternionToAngleAxis to ensure rotations are between -pi and pi.
+ Change NumericDiffCostFunction to accept variadic functors.
+
+ The interface for NumericDiffCostFunction and AutoDiffCostFunction
+ are not comparable. They both accept variadic functors.
- Thanks to Guoxuan Zhang for reporting this.
+ The change is backward compatible, as it still supports numeric
+ differentiation of CostFunction objects.
- Change-Id: I2831ca3a04d5dc6467849c290461adbe23faaea3
+ Some refactoring of documentation and code in auto_diff_cost_function
+ and its relatives was also done to make things consistent.
+
+ Change-Id: Ib5f230a1d4a85738eb187803b9c1cd7166bb3b92
-commit dd2b17d7dd9750801ba4720bdece2062e59b7ae3
+commit 9c5acce674e3ec1ba08509123ff519f106cc4348
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 16 19:34:57 2012 -0700
+Date: Sun Jan 13 22:14:12 2013 -0800
- CERES_DONT_HAVE_PROTOCOL_BUFFERS -> CERES_NO_PROTOCOL_BUFFERS.
+ Add CostFunctionToFunctor.
+
+ CostFunctionToFunctor wraps a CostFunction, and makes it available
+ as a templated functor that can be called from other templated
+ functors. This is useful for when one wants to mix automatic,
+ numeric and analytic differentiated functions.
+
+ Also a bug fix in autodiff.h
- Change-Id: I6c9f50e4c006faf4e75a8f417455db18357f3187
+ Change-Id: If8ba281a89fda976ef2ce10a5844a74c4ac7b84a
-commit 8b4cb7aa2c74a0da62c638b2023566aa242af995
+commit c89ea4b9de588e2e2e82c54cd1c30cddb11454c5
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 16 19:26:55 2012 -0700
+Date: Wed Jan 9 16:09:35 2013 -0800
- Fix sparse linear algebra library logging in Summary::FullReport.
+ Minor corrections based on Jim Roseborough's comments
- Change-Id: Id2c902dc86c00954fde7749c7b4a67dd94215a31
+ Change-Id: I4a8c7a454ddf038a3ed2567c101f9aee582044bf
-commit 47d26bcd3b38b5ff53b34768c33b499d47b26bd0
-Author: Markus Moll <markus.moll@esat.kuleuven.be>
-Date: Thu Aug 16 00:23:38 2012 +0200
+commit 00c8a061929b912bda3cfd4615fb8688c246c969
+Author: Keir Mierle <mierle@gmail.com>
+Date: Sat Dec 1 13:22:59 2012 -0800
- Do not implicitly negate the step in the TrustRegionMinimizer.
-
- In the TrustRegionMinimizer, the step is currently implicitly negated.
- This is done so that the linearized residual is |r - J*step|^2, which
- corresponds to J*step = r, so neither J nor r have to be modified.
- However, it leads to the rather unintuitive situation that the strategy
- returns a step in positive gradient direction, which you would expect to
- increase the function value. One way is to rename the "step" parameter in
- the strategy to "negative_step" and document it.
- This patch instead moves the negation inside the strategy, just around
- the linear solver call, so that it is done in a local context and easier
- to document.
+ Fix bug in DenseSparseMatrix::ToDenseMatrix().
- Change-Id: Idb258149a01f61c64e22128ea221c5a30cd89c89
+ Change-Id: I74a1a03149d74fbc4268ec3ce9d20e09746a7227
-commit 51da590c8457e6664f76fe9813425a0c71351497
-Author: Markus Moll <markus.moll@esat.kuleuven.be>
-Date: Fri Aug 17 12:56:09 2012 +0200
+commit bcac4de5b75cae210c5557c81239222176d2709a
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Fri Nov 30 23:11:26 2012 -0800
- Remove tmp file
+ Speedup corrector.cc
+
+ Add a specialization for the common case where the residual block
+ outputs exactly one residual.
- Change-Id: I07496fafae7b0c5c12cc26ae336e0db3b5592735
+ The matrix routines used by Corrector can be then specialized to
+ a scalar and be made considerably faster.
+
+ For denoising upto 400% speedup is observed.
+
+ Change-Id: I8e3f24b8ba41caa8e62ad97c5f5e96ab6ea47150
-commit 7006a1f2b1701b8d89b8d1525fc0101943802221
+commit 9883fc396b2913fbc597afa795c39d365229c299
Author: Sameer Agarwal <sameeragarwal@google.com>
-Date: Thu Aug 16 18:04:22 2012 -0700
+Date: Fri Nov 30 12:32:43 2012 -0800
- Correct example code in Powell's function example.
+ Refactoring of the LineSearchMinimizer.
- Thanks to Petter Strandmark for pointing this out.
+ 1. New LineSearchDirection interface, factory and instances.
+ 2. Cleanup of LineSearchMinimizer to use the State and Direction objects.
+ 3. LBFGS -> LowRankInverseHessian.
+ 4. Refactoring of the RunCallbacks function and share it across
+ LineSearchMinimizer and TrustRegionMinimizer.
- Change-Id: I967632235dccdb481396e94904bb911c9a1efe1e
+ Change-Id: I19354afc6f5d6567b28918710c2012dc30ef8f32
-commit 57a44b27bc6fc95b4e70fdc25c25c9925a2072a0
-Author: Keir Mierle <mierle@gmail.com>
-Date: Thu Aug 16 17:04:50 2012 -0700
+commit 2293cb5bc96a5b317ed4ca52aa3494cadecbc07c
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Thu Nov 29 16:00:18 2012 -0800
- Remove unnecessary flags in NDK build.
+ Add missing documentation to solver.h
- Change-Id: Ib5b4d0b7f2d898671252734978c789b8171d96a8
+ Change-Id: I86e7c4f1f6cc1e15d5eb2cf23e73c32d94d458c1
-commit f21bee247251a8b2e836c215a84c4668c31d75cd
-Author: Keir Mierle <mierle@gmail.com>
-Date: Thu Aug 16 16:27:10 2012 -0700
+commit aed99615c017839df09c98f518dcc0a59a9819ec
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Thu Nov 29 10:33:19 2012 -0800
- Fix for fpclassify.h NDK porting work.
+ Expose lbfgs rank in solver.h
- Change-Id: I69df1b4caf2941ed96a53e35e43ec54073f84f59
+ Change-Id: Ibc184b1a2f94a4057fa6569d539ca3a55d6d6098
-commit 8ceb02cb75b66602de44a35e413225386cb21c27
-Author: Keir Mierle <mierle@gmail.com>
-Date: Thu Aug 16 14:23:47 2012 -0700
+commit 1afd498f50ef520868c18a0f26b55409d8471ceb
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Thu Nov 29 10:28:11 2012 -0800
- Add Android NDK build files.
+ String to and from enum conversion routines.
+
+ Update types.h/cc with stringication and unstringication
+ routines for the newly introduced enums.
- This adds a Android.mk build that builds a Ceres static library
- suitable for embetting in larger Android applications. This is
- useful when needing to build Ceres without GPL'd components, since
- the standalone toolchain (needed for the CMake Android build) does
- not work with STLPort.
+ Change-Id: I0fe2842b5b1c75ba351f4ab87ec9fa60af2f9ed2
+
+commit 3e8d192f2871bcf6d5f248c119c8a6eef19186d3
+Author: Sameer Agarwal <sameeragarwal@google.com>
+Date: Wed Nov 28 17:20:22 2012 -0800
+
+ Add a rough implementation of LBFGS.
- Change-Id: I8d857237f6f82658741017d161b2e31d9a20e5a7
+ Change-Id: I2bc816adfe0c02773a23035ea31de3cddc1322a4
diff --git a/extern/libmv/third_party/ceres/SConscript b/extern/libmv/third_party/ceres/SConscript
index 6d0d2cd5c40..6e490cfd5cf 100644
--- a/extern/libmv/third_party/ceres/SConscript
+++ b/extern/libmv/third_party/ceres/SConscript
@@ -23,6 +23,10 @@ defs.append('CERES_NO_SUITESPARSE')
defs.append('CERES_NO_CXSPARSE')
defs.append('CERES_NO_PROTOCOL_BUFFERS')
defs.append('CERES_RESTRICT_SCHUR_SPECIALIZATION')
+defs.append('CERES_HAVE_RWLOCK')
+
+if env['WITH_BF_OPENMP']:
+ defs.append('CERES_USE_OPENMP')
if 'Mac OS X 10.5' in env['MACOSX_SDK_CHECK']:
defs.append('CERES_NO_TR1')
diff --git a/extern/libmv/third_party/ceres/bundle.sh b/extern/libmv/third_party/ceres/bundle.sh
index 76630bc0626..65af263f7c4 100755
--- a/extern/libmv/third_party/ceres/bundle.sh
+++ b/extern/libmv/third_party/ceres/bundle.sh
@@ -9,7 +9,8 @@ fi
repo="https://ceres-solver.googlesource.com/ceres-solver"
branch="master"
-tag="1.3.0"
+#tag="1.4.0"
+tag=""
tmp=`mktemp -d`
checkout="$tmp/ceres"
@@ -120,7 +121,7 @@ set(INC
include
internal
../gflags
- ../..
+ ../../
)
set(INC_SYS
@@ -161,8 +162,15 @@ add_definitions(
-DCERES_NO_CXSPARSE
-DCERES_NO_PROTOCOL_BUFFERS
-DCERES_RESTRICT_SCHUR_SPECIALIZATION
+ -DCERES_HAVE_RWLOCK
)
+if(WITH_OPENMP)
+ add_definitions(
+ -DCERES_USE_OPENMP
+ )
+endif()
+
if(MSVC10)
add_definitions(
-D"CERES_HASH_NAMESPACE_START=namespace std {"
@@ -212,6 +220,10 @@ defs.append('CERES_NO_SUITESPARSE')
defs.append('CERES_NO_CXSPARSE')
defs.append('CERES_NO_PROTOCOL_BUFFERS')
defs.append('CERES_RESTRICT_SCHUR_SPECIALIZATION')
+defs.append('CERES_HAVE_RWLOCK')
+
+if env['WITH_BF_OPENMP']:
+ defs.append('CERES_USE_OPENMP')
if 'Mac OS X 10.5' in env['MACOSX_SDK_CHECK']:
defs.append('CERES_NO_TR1')
diff --git a/extern/libmv/third_party/ceres/files.txt b/extern/libmv/third_party/ceres/files.txt
index 55083572977..8f4b7b97b50 100644
--- a/extern/libmv/third_party/ceres/files.txt
+++ b/extern/libmv/third_party/ceres/files.txt
@@ -2,21 +2,28 @@ include/ceres/autodiff_cost_function.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/crs_matrix.h
+include/ceres/dynamic_autodiff_cost_function.h
include/ceres/fpclassify.h
+include/ceres/gradient_checker.h
include/ceres/internal/autodiff.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/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_functor.h
+include/ceres/ordered_groups.h
include/ceres/problem.h
include/ceres/rotation.h
include/ceres/sized_cost_function.h
@@ -54,6 +61,8 @@ 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/cxsparse.cc
@@ -71,6 +80,7 @@ internal/ceres/dogleg_strategy.cc
internal/ceres/dogleg_strategy.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/schur_eliminator_2_2_2.cc
@@ -107,18 +117,31 @@ 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/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/matrix_proto.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/polynomial_solver.cc
-internal/ceres/polynomial_solver.h
+internal/ceres/polynomial.cc
+internal/ceres/polynomial.h
+internal/ceres/preconditioner.cc
+internal/ceres/preconditioner.h
internal/ceres/problem.cc
internal/ceres/problem_impl.cc
internal/ceres/problem_impl.h
@@ -137,8 +160,8 @@ 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_ordering.cc
-internal/ceres/schur_ordering.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/solver.cc
@@ -166,3 +189,5 @@ 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
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
index da9ee2c7993..e758d3a2bd5 100644
--- a/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h
+++ b/extern/libmv/third_party/ceres/include/ceres/autodiff_cost_function.h
@@ -28,10 +28,10 @@
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
//
-// Helpers for making 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
+// 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
@@ -57,8 +57,8 @@
// To write an auto-differentiable cost function for the above model, first
// define the object
//
-// class MyScalarCostFunction {
-// MyScalarCostFunction(double k): k_(k) {}
+// class MyScalarCostFunctor {
+// MyScalarCostFunctor(double k): k_(k) {}
//
// template <typename T>
// bool operator()(const T* const x , const T* const y, T* e) const {
@@ -80,32 +80,32 @@
// it can be constructed as follows.
//
// CostFunction* cost_function
-// = new AutoDiffCostFunction<MyScalarCostFunction, 1, 2, 2>(
-// new MyScalarCostFunction(1.0)); ^ ^ ^
-// | | |
-// Dimension of residual ------+ | |
-// Dimension of x ----------------+ |
-// Dimension of y -------------------+
+// = 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
-// "MyScalarCostFunction", "1, 2, 2", describe the functor as computing a
+// "MyScalarCostFunctor", "1, 2, 2", describe the functor as computing a
// 1-dimensional output from two arguments, both 2-dimensional.
//
// The autodiff cost function also supports cost functions with a
// runtime-determined number of residuals. For example:
//
// CostFunction* cost_function
-// = new AutoDiffCostFunction<MyScalarCostFunction, DYNAMIC, 2, 2>(
-// new CostFunctionWithDynamicNumResiduals(1.0), ^ ^ ^
-// runtime_number_of_residuals); <----+ | | |
-// | | | |
-// | | | |
-// Actual number of residuals ------+ | | |
-// Indicate dynamic number of residuals ---------+ | |
-// Dimension of x -------------------------------------+ |
-// Dimension of y ----------------------------------------+
+// = 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 6 independent
// variables, and there is no limit on the dimensionality of each of them.
@@ -119,7 +119,7 @@
// 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 <MyScalarCostFunction, 1, 2>, which is missing
+// 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_
@@ -154,16 +154,21 @@ template <typename CostFunctor,
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.
-class AutoDiffCostFunction :
- public SizedCostFunction<M, N0, N1, N2, N3, N4, N5> {
+ 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<M,
+ 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 ("M").
explicit AutoDiffCostFunction(CostFunctor* functor)
: functor_(functor) {
CHECK_NE(M, DYNAMIC) << "Can't run the fixed-size constructor if the "
- << "number of residuals is set to ceres::DYNAMIC.";
+ << "number of residuals is set to ceres::DYNAMIC.";
}
// Takes ownership of functor. Ignores the template-provided number of
@@ -174,8 +179,9 @@ class AutoDiffCostFunction :
AutoDiffCostFunction(CostFunctor* functor, int num_residuals)
: functor_(functor) {
CHECK_EQ(M, DYNAMIC) << "Can't run the dynamic-size constructor if the "
- << "number of residuals is not ceres::DYNAMIC.";
- SizedCostFunction<M, N0, N1, N2, N3, N4, N5>::set_num_residuals(num_residuals);
+ << "number of residuals is not ceres::DYNAMIC.";
+ SizedCostFunction<M, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>
+ ::set_num_residuals(num_residuals);
}
virtual ~AutoDiffCostFunction() {}
@@ -190,14 +196,15 @@ class AutoDiffCostFunction :
double** jacobians) const {
if (!jacobians) {
return internal::VariadicEvaluate<
- CostFunctor, double, N0, N1, N2, N3, N4, N5>
+ 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>::Differentiate(
+ N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Differentiate(
*functor_,
parameters,
- SizedCostFunction<M, N0, N1, N2, N3, N4, N5>::num_residuals(),
+ SizedCostFunction<M, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>
+ ::num_residuals(),
residuals,
jacobians);
}
diff --git a/extern/libmv/third_party/ceres/include/ceres/ceres.h b/extern/libmv/third_party/ceres/include/ceres/ceres.h
index 22aaf8ff21a..7878806aa45 100644
--- a/extern/libmv/third_party/ceres/include/ceres/ceres.h
+++ b/extern/libmv/third_party/ceres/include/ceres/ceres.h
@@ -34,12 +34,20 @@
#ifndef CERES_PUBLIC_CERES_H_
#define CERES_PUBLIC_CERES_H_
+#define CERES_VERSION 1.5.0
+#define CERES_ABI_VERSION 1.5.0
+
#include "ceres/autodiff_cost_function.h"
#include "ceres/cost_function.h"
+#include "ceres/cost_function_to_functor.h"
+#include "ceres/crs_matrix.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/numeric_diff_functor.h"
+#include "ceres/ordered_groups.h"
#include "ceres/problem.h"
#include "ceres/sized_cost_function.h"
#include "ceres/solver.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
new file mode 100644
index 00000000000..b30ecd06983
--- /dev/null
+++ b/extern/libmv/third_party/ceres/include/ceres/cost_function_to_functor.h
@@ -0,0 +1,752 @@
+// 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_GE(kNumResiduals, 0);
+ CHECK_EQ(cost_function->num_residuals(), kNumResiduals);
+
+ // 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<int16>& 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<int16>& 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 int16 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/crs_matrix.h b/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h
index c9fe8f78b7c..8c470cd33f2 100644
--- a/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h
+++ b/extern/libmv/third_party/ceres/include/ceres/crs_matrix.h
@@ -44,17 +44,35 @@ struct CRSMatrix {
int num_rows;
int num_cols;
- // A compressed row matrix stores its contents in three arrays.
- // The non-zero pattern of the i^th row is given by
+ // A compressed row matrix stores its contents in three arrays,
+ // rows, cols and values.
//
- // rows[cols[i] ... cols[i + 1]]
+ // rows is a num_rows + 1 sized array that points into the cols and
+ // values array. For each row i:
//
- // and the corresponding values by
+ // cols[rows[i]] ... cols[rows[i + 1] - 1] are the indices of the
+ // non-zero columns of row i.
//
- // values[cols[i] ... cols[i + 1]]
+ // values[rows[i]] .. values[rows[i + 1] - 1] are the values of the
+ // corresponding entries.
//
- // Thus, cols is a vector of size num_cols + 1, and rows and values
- // have as many entries as number of non-zeros in the matrix.
+ // 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;
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
new file mode 100644
index 00000000000..861164a8253
--- /dev/null
+++ b/extern/libmv/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h
@@ -0,0 +1,215 @@
+// 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 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, NULL);
+ int num_active_parameters = 0;
+ int start_derivative_section = -1;
+ for (int i = 0, parameter_cursor = 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) {
+ start_derivative_section =
+ (start_derivative_section == -1)
+ ? parameter_cursor
+ : start_derivative_section;
+ num_active_parameters += parameter_block_size;
+ }
+
+ for (int j = 0; j < parameter_block_size; ++j, parameter_cursor++) {
+ input_jets[parameter_cursor].a = parameters[i][j];
+ }
+ }
+
+ // 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)));
+
+ for (int pass = 0; pass < num_strides; ++pass) {
+ // Set most of the jet components to zero, except for
+ // non-constant #Stride parameters.
+ int active_parameter_count = 0;
+ int end_derivative_section = start_derivative_section;
+ for (int i = 0, parameter_cursor = 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 (parameter_cursor >= start_derivative_section &&
+ active_parameter_count < Stride) {
+ if (jacobians[i] != NULL) {
+ input_jets[parameter_cursor]
+ .v[parameter_cursor - start_derivative_section] = 1.0;
+ ++active_parameter_count;
+ }
+ ++end_derivative_section;
+ }
+ }
+ }
+
+ if (!(*functor_)(&jet_parameters[0], &output_jets[0])) {
+ return false;
+ }
+
+ // Copy the pieces of the jacobians into their final place.
+ active_parameter_count = 0;
+ 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 (parameter_cursor >= start_derivative_section &&
+ active_parameter_count < Stride) {
+ if (jacobians[i] != NULL) {
+ for (int k = 0; k < num_residuals(); ++k) {
+ jacobians[i][k * parameter_block_sizes()[i] + j] =
+ output_jets[k].v[parameter_cursor -
+ start_derivative_section];
+ }
+ ++active_parameter_count;
+ }
+ }
+ }
+ }
+
+ // 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;
+ }
+ }
+
+ start_derivative_section = end_derivative_section;
+ }
+ 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/fpclassify.h b/extern/libmv/third_party/ceres/include/ceres/fpclassify.h
index 5a9ea1599d2..b730832fd4b 100644
--- a/extern/libmv/third_party/ceres/include/ceres/fpclassify.h
+++ b/extern/libmv/third_party/ceres/include/ceres/fpclassify.h
@@ -41,6 +41,8 @@
#include <float.h>
#endif
+#include <limits>
+
namespace ceres {
#if defined(_MSC_VER)
diff --git a/extern/libmv/third_party/ceres/include/ceres/gradient_checker.h b/extern/libmv/third_party/ceres/include/ceres/gradient_checker.h
new file mode 100644
index 00000000000..3ec8056a02d
--- /dev/null
+++ b/extern/libmv/third_party/ceres/include/ceres/gradient_checker.h
@@ -0,0 +1,222 @@
+// 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<int16>& 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/internal/autodiff.h b/extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h
index 4f5081f8f66..011f2a05b65 100644
--- a/extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h
+++ b/extern/libmv/third_party/ceres/include/ceres/internal/autodiff.h
@@ -146,6 +146,7 @@
#include "ceres/jet.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/variadic_evaluate.h"
namespace ceres {
namespace internal {
@@ -191,134 +192,71 @@ 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);
+ Eigen::Map<Eigen::Matrix<T, N, 1> >(dst + N * i, N) =
+ src[i].v.template segment<N>(N0);
}
}
-// 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.
-//
-// Supporting variadic functions is the primary source of complexity in the
-// autodiff implementation.
-
-template<typename Functor, typename T,
- int N0, int N1, int N2, int N3, int N4, int N5>
-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],
- 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> {
- 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> {
- 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> {
- 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> {
- 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> {
- static bool Call(const Functor& functor, T const *const *input, T* output) {
- return functor(input[0],
- output);
- }
-};
-
-// 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.
+// 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 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) {
- typedef Jet<T, N0 + N1 + N2 + N3 + N4 + N5> JetT;
-
- DCHECK_GT(N0, 0)
- << "Cost functions must have at least one parameter block.";
- DCHECK((!N1 && !N2 && !N3 && !N4 && !N5) ||
- ((N1 > 0) && !N2 && !N3 && !N4 && !N5) ||
- ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0)))
+ // This block breaks the 80 column rule to keep it somewhat readable.
+ DCHECK_GT(num_outputs, 0);
+ 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;
-
- DCHECK_GT(num_outputs, 0);
+ << 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 + num_outputs);
+ N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9 + num_outputs);
- // It's ugly, but it works.
- 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;
+ // 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[6] = {
+ 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() + jet6;
+
+ JetT* output = x.get() + N0 + N1 + N2 + N3 + N4 + N5 + N6 + N7 + N8 + N9;
#define CERES_MAKE_1ST_ORDER_PERTURBATION(i) \
if (N ## i) { \
@@ -333,10 +271,14 @@ struct AutoDiff {
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>::Call(
+ N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Call(
functor, unpacked_parameters, output)) {
return false;
}
@@ -359,6 +301,10 @@ struct AutoDiff {
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;
}
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
index ce777d22dc7..fa4a339d757 100644
--- a/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h
+++ b/extern/libmv/third_party/ceres/include/ceres/internal/fixed_array.h
@@ -168,11 +168,11 @@ inline FixedArray<T, S>::FixedArray(typename FixedArray<T, S>::size_type n)
array_((n <= kInlineElements
? reinterpret_cast<InnerContainer*>(inline_space_)
: new InnerContainer[n])) {
- DCHECK_GE(n, 0);
+ DCHECK_GE(n, size_t(0));
// Construct only the elements actually used.
if (array_ == reinterpret_cast<InnerContainer*>(inline_space_)) {
- for (int i = 0; i != size_; ++i) {
+ for (size_t i = 0; i != size_; ++i) {
inline_space_[i].Init();
}
}
@@ -183,7 +183,7 @@ inline FixedArray<T, S>::~FixedArray() {
if (array_ != reinterpret_cast<InnerContainer*>(inline_space_)) {
delete[] array_;
} else {
- for (int i = 0; i != size_; ++i) {
+ for (size_t i = 0; i != size_; ++i) {
inline_space_[i].Destroy();
}
}
diff --git a/extern/libmv/third_party/ceres/include/ceres/internal/macros.h b/extern/libmv/third_party/ceres/include/ceres/internal/macros.h
index 83ec31193e7..388cf30fe70 100644
--- a/extern/libmv/third_party/ceres/include/ceres/internal/macros.h
+++ b/extern/libmv/third_party/ceres/include/ceres/internal/macros.h
@@ -132,16 +132,16 @@ char (&ArraySizeHelper(const T (&array)[N]))[N];
// - 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
+// 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))) / \
+#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:
+// 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;
//
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
index 174d35ee2bd..7ea723d2a83 100644
--- a/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h
+++ b/extern/libmv/third_party/ceres/include/ceres/internal/manual_constructor.h
@@ -110,56 +110,61 @@ class ManualConstructor {
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;
+ new(space()) Type;
}
template <typename T1>
inline void Init(const T1& p1) {
- new(space_) Type(p1);
+ new(space()) Type(p1);
}
template <typename T1, typename T2>
inline void Init(const T1& p1, const T2& p2) {
- new(space_) Type(p1, 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
@@ -167,7 +172,7 @@ class ManualConstructor {
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);
+ new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
@@ -175,7 +180,7 @@ class ManualConstructor {
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);
+ new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
}
template <typename T1, typename T2, typename T3, typename T4, typename T5,
@@ -184,7 +189,7 @@ class ManualConstructor {
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);
+ new(space()) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);
}
inline void Destroy() {
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
new file mode 100644
index 00000000000..4058366c4a1
--- /dev/null
+++ b/extern/libmv/third_party/ceres/include/ceres/internal/numeric_diff.h
@@ -0,0 +1,199 @@
+// 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,
+ double **parameters,
+ double *jacobian) {
+ using Eigen::Map;
+ using Eigen::Matrix;
+ using Eigen::RowMajor;
+ using Eigen::ColMajor;
+
+ typedef Matrix<double, kNumResiduals, 1> ResidualVector;
+ typedef Matrix<double, kParameterBlockSize, 1> ParameterVector;
+ typedef Matrix<double, kNumResiduals, kParameterBlockSize,
+ (kParameterBlockSize == 1 &&
+ kNumResiduals > 1) ? ColMajor : RowMajor> JacobianMatrix;
+
+
+ Map<JacobianMatrix> parameter_jacobian(jacobian,
+ kNumResiduals,
+ 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.
+ 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;
+
+ double residuals[kNumResiduals]; // NOLINT
+
+ if (!EvaluateImpl<CostFunctor, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>(
+ functor, parameters, residuals, 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) =
+ Map<const ResidualVector>(residuals, kNumResiduals);
+
+ 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, functor)) {
+ return false;
+ }
+
+ parameter_jacobian.col(j) -=
+ Map<ResidualVector>(residuals, kNumResiduals, 1);
+ one_over_delta /= 2;
+ } else {
+ // Forward difference only; reuse existing residuals evaluation.
+ parameter_jacobian.col(j) -=
+ Map<const ResidualVector>(residuals_at_eval_point, kNumResiduals);
+ }
+ 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,
+ 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/scoped_ptr.h b/extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h
index 44f198b339d..5dfb551243c 100644
--- a/extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h
+++ b/extern/libmv/third_party/ceres/include/ceres/internal/scoped_ptr.h
@@ -38,6 +38,7 @@
#include <assert.h>
#include <stdlib.h>
#include <cstddef>
+#include <algorithm>
namespace ceres {
namespace internal {
@@ -49,18 +50,17 @@ 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.
+// 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;
@@ -193,7 +193,6 @@ scoped_ptr<C> make_scoped_ptr(C *p) {
template <class C>
class scoped_array {
public:
-
// The element type
typedef C element_type;
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
new file mode 100644
index 00000000000..4b1e4bdc65a
--- /dev/null
+++ b/extern/libmv/third_party/ceres/include/ceres/internal/variadic_evaluate.h
@@ -0,0 +1,182 @@
+// 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 <glog/logging.h>
+#include "ceres/jet.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/fixed_array.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
index 29157d380f2..0dc4c96b441 100644
--- a/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h
+++ b/extern/libmv/third_party/ceres/include/ceres/iteration_callback.h
@@ -42,6 +42,23 @@ namespace ceres {
// This struct describes the state of the optimizer after each
// iteration of the minimization.
struct 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),
+ step_norm(0.0),
+ eta(0.0),
+ step_size(0.0),
+ line_search_function_evaluations(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;
@@ -51,7 +68,22 @@ struct IterationSummary {
// Note: step_is_valid is false when iteration = 0.
bool step_is_valid;
- // Whether or not the algorithm made progress in this iteration.
+ // 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;
@@ -60,8 +92,7 @@ struct IterationSummary {
double cost;
// Change in the value of the objective function in this
- // iteration. This can be positive or negative. Negative change
- // means that the step was not successful.
+ // iteration. This can be positive or negative.
double cost_change;
// Infinity norm of the gradient vector.
@@ -87,6 +118,12 @@ struct IterationSummary {
// ignore it.
double eta;
+ // Step sized computed by the line search algorithm.
+ double step_size;
+
+ // Number of function evaluations used by the line search algorithm.
+ int line_search_function_evaluations;
+
// Number of iterations taken by the linear solver to solve for the
// Newton step.
int linear_solver_iterations;
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
index 8544e44d0bc..555bc3d073f 100644
--- 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
@@ -27,19 +27,109 @@
// 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 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 nececssary 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.
+// 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.
+//
+// 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 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.
+//
+// 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.
+//
+// TODO(sameeragarwal): Add support for dynamic number of residuals.
+//
+// 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 nececssary 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:
@@ -51,233 +141,153 @@
// where MyCostFunction has 1 residual and 2 parameter blocks with sizes 4 and 8
// respectively. Look at the tests for a more detailed example.
//
-// 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.
-//
// 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 <cstring>
#include <glog/logging.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"
namespace ceres {
-enum NumericDiffMethod {
- CENTRAL,
- FORWARD
-};
-
-// 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 CostFunctionNoJacobian,
- int num_residuals,
- int parameter_block_size,
- int parameter_block,
- NumericDiffMethod method>
-struct Differencer {
- // Mutates parameters but must restore them before return.
- static bool EvaluateJacobianForParameterBlock(
- const CostFunctionNoJacobian *function,
- double const* residuals_at_eval_point,
- double **parameters,
- double **jacobians) {
- using Eigen::Map;
- using Eigen::Matrix;
- using Eigen::RowMajor;
- using Eigen::ColMajor;
-
- typedef Matrix<double, num_residuals, 1> ResidualVector;
- typedef Matrix<double, parameter_block_size, 1> ParameterVector;
- typedef Matrix<double, num_residuals, parameter_block_size,
- (parameter_block_size == 1 &&
- num_residuals > 1) ? ColMajor : RowMajor> JacobianMatrix;
-
- Map<JacobianMatrix> parameter_jacobian(jacobians[parameter_block],
- num_residuals,
- parameter_block_size);
-
- // Mutate 1 element at a time and then restore.
- Map<ParameterVector> x_plus_delta(parameters[parameter_block],
- parameter_block_size);
- ParameterVector x(x_plus_delta);
-
- // TODO(keir): Pick a smarter number! 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.
- const double kRelativeStepSize = 1e-6;
-
- ParameterVector step_size = x.array().abs() * kRelativeStepSize;
-
- // To handle cases where a parameter 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. Take
- // kRelativeStepSize as a guess and hope for the best.
- fallback_step_size = kRelativeStepSize;
- }
-
- // 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);
-
- double residuals[num_residuals]; // NOLINT
- if (!function->Evaluate(parameters, residuals, NULL)) {
- // 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) =
- Map<const ResidualVector>(residuals, num_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 (!function->Evaluate(parameters, residuals, NULL)) {
- // Something went wrong; bail.
- return false;
- }
- parameter_jacobian.col(j) -=
- Map<ResidualVector>(residuals, num_residuals, 1);
- 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;
- }
-};
-
-// Prevent invalid instantiations.
-template <typename CostFunctionNoJacobian,
- int num_residuals,
- int parameter_block,
- NumericDiffMethod method>
-struct Differencer<CostFunctionNoJacobian,
- num_residuals,
- 0 /* parameter_block_size */,
- parameter_block,
- method> {
- static bool EvaluateJacobianForParameterBlock(
- const CostFunctionNoJacobian *function,
- double const* residuals_at_eval_point,
- double **parameters,
- double **jacobians) {
- LOG(FATAL) << "Shouldn't get here.";
- return true;
- }
-};
-
-template <typename CostFunctionNoJacobian,
- NumericDiffMethod method = CENTRAL, int M = 0,
- int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0, int N5 = 0>
+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<M, N0, N1, N2, N3, N4, N5> {
+ : public SizedCostFunction<kNumResiduals,
+ N0, N1, N2, N3, N4,
+ N5, N6, N7, N8, N9> {
public:
- NumericDiffCostFunction(CostFunctionNoJacobian* function,
- Ownership ownership)
- : function_(function), ownership_(ownership) {}
+ NumericDiffCostFunction(CostFunctor* functor,
+ const double relative_step_size = 1e-6)
+ :functor_(functor),
+ ownership_(TAKE_OWNERSHIP),
+ relative_step_size_(relative_step_size) {}
- virtual ~NumericDiffCostFunction() {
+ NumericDiffCostFunction(CostFunctor* functor,
+ Ownership ownership,
+ const double relative_step_size = 1e-6)
+ : functor_(functor),
+ ownership_(ownership),
+ relative_step_size_(relative_step_size) {}
+
+ ~NumericDiffCostFunction() {
if (ownership_ != TAKE_OWNERSHIP) {
- function_.release();
+ 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.
- bool success = function_->Evaluate(parameters, residuals, NULL);
- if (!success) {
- // Something went wrong; ignore the jacobian.
+ if (!internal::EvaluateImpl<CostFunctor,
+ N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>(
+ functor_.get(),
+ parameters,
+ residuals,
+ functor_.get())) {
return false;
}
+
if (!jacobians) {
- // Nothing to do; just forward.
return true;
}
// Create a copy of the parameters which will get mutated.
- const int kParametersSize = N0 + N1 + N2 + N3 + N4 + N5;
- double parameters_copy[kParametersSize];
- double *parameters_references_copy[6];
- parameters_references_copy[0] = &parameters_copy[0];
- parameters_references_copy[1] = &parameters_copy[0] + N0;
- parameters_references_copy[2] = &parameters_copy[0] + N0 + N1;
- parameters_references_copy[3] = &parameters_copy[0] + N0 + N1 + N2;
- parameters_references_copy[4] = &parameters_copy[0] + N0 + N1 + N2 + N3;
- parameters_references_copy[5] =
- &parameters_copy[0] + N0 + N1 + N2 + N3 + N4;
+ 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 (N7) parameters_reference_copy[8] = parameters_reference_copy[7] + N7;
+ if (N8) 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
-#define COPY_PARAMETER_BLOCK(block) \
- if (N ## block) memcpy(parameters_references_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]) { \
- if (!Differencer<CostFunctionNoJacobian, /* NOLINT */ \
- M, \
- N ## block, \
- block, \
- method>::EvaluateJacobianForParameterBlock( \
- function_.get(), \
- residuals, \
- parameters_references_copy, \
- jacobians)) { \
- return false; \
- } \
+#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_, \
+ 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<CostFunctionNoJacobian> function_;
+ internal::scoped_ptr<CostFunctor> functor_;
Ownership ownership_;
+ const double relative_step_size_;
};
} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/include/ceres/numeric_diff_functor.h b/extern/libmv/third_party/ceres/include/ceres/numeric_diff_functor.h
new file mode 100644
index 00000000000..593c3718bf5
--- /dev/null
+++ b/extern/libmv/third_party/ceres/include/ceres/numeric_diff_functor.h
@@ -0,0 +1,346 @@
+// 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)
+//
+// A wrapper class that takes a variadic functor evaluating a
+// function, numerically differentiates it and makes it available as a
+// templated functor so that it can be easily used as part of Ceres'
+// automatic differentiation framework.
+//
+// For example:
+//
+// For example, let us assume that
+//
+// struct IntrinsicProjection
+// IntrinsicProjection(const double* observations);
+// bool operator()(const double* calibration,
+// const double* point,
+// double* residuals);
+// };
+//
+// is a functor that implements the projection of a point in its local
+// coordinate system onto its image plane and subtracts it from the
+// observed point projection.
+//
+// Now we would like to compose the action of this functor with the
+// action of camera extrinsics, i.e., rotation and translation, which
+// is given by the following templated function
+//
+// template<typename T>
+// void RotateAndTranslatePoint(const T* rotation,
+// const T* translation,
+// const T* point,
+// T* result);
+//
+// To compose the extrinsics and intrinsics, we can construct a
+// CameraProjection functor as follows.
+//
+// struct CameraProjection {
+// typedef NumericDiffFunctor<IntrinsicProjection, CENTRAL, 2, 5, 3>
+// IntrinsicProjectionFunctor;
+//
+// CameraProjection(double* observation) {
+// intrinsic_projection_.reset(
+// new IntrinsicProjectionFunctor(observation)) {
+// }
+//
+// template <typename T>
+// bool operator(const T* rotation,
+// const T* translation,
+// const T* intrinsics,
+// const T* point,
+// T* residuals) const {
+// T transformed_point[3];
+// RotateAndTranslatePoint(rotation, translation, point, transformed_point);
+// return (*intrinsic_projection_)(intrinsics, transformed_point, residual);
+// }
+//
+// private:
+// scoped_ptr<IntrinsicProjectionFunctor> intrinsic_projection_;
+// };
+//
+// Here, we made the choice of using CENTRAL differences to compute
+// the jacobian of IntrinsicProjection.
+//
+// Now, we are ready to construct an automatically differentiated cost
+// function as
+//
+// CostFunction* cost_function =
+// new AutoDiffCostFunction<CameraProjection, 2, 3, 3, 5>(
+// new CameraProjection(observations));
+//
+// cost_function now seamlessly integrates automatic differentiation
+// of RotateAndTranslatePoint with a numerically differentiated
+// version of IntrinsicProjection.
+
+#ifndef CERES_PUBLIC_NUMERIC_DIFF_FUNCTOR_H_
+#define CERES_PUBLIC_NUMERIC_DIFF_FUNCTOR_H_
+
+#include "ceres/numeric_diff_cost_function.h"
+#include "ceres/types.h"
+#include "ceres/cost_function_to_functor.h"
+
+namespace ceres {
+
+template<typename Functor,
+ NumericDiffMethod kMethod = CENTRAL,
+ int kNumResiduals = 0,
+ 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 NumericDiffFunctor {
+ public:
+ // relative_step_size controls the step size used by the numeric
+ // differentiation process.
+ explicit NumericDiffFunctor(double relative_step_size = 1e-6)
+ : functor_(
+ new NumericDiffCostFunction<Functor,
+ kMethod,
+ kNumResiduals,
+ N0, N1, N2, N3, N4,
+ N5, N6, N7, N8, N9>(new Functor,
+ relative_step_size)) {
+ }
+
+ NumericDiffFunctor(Functor* functor, double relative_step_size = 1e-6)
+ : functor_(new NumericDiffCostFunction<Functor,
+ kMethod,
+ kNumResiduals,
+ N0, N1, N2, N3, N4,
+ N5, N6, N7, N8, N9>(
+ functor, relative_step_size)) {
+ }
+
+ bool operator()(const double* x0, double* residuals) const {
+ return functor_(x0, residuals);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ double* residuals) const {
+ return functor_(x0, x1, residuals);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ const double* x2,
+ double* residuals) const {
+ return functor_(x0, x1, x2, residuals);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ const double* x2,
+ const double* x3,
+ double* residuals) const {
+ return functor_(x0, x1, x2, x3, residuals);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ const double* x2,
+ const double* x3,
+ const double* x4,
+ double* residuals) const {
+ return functor_(x0, x1, x2, x3, x4, residuals);
+ }
+
+ bool operator()(const double* x0,
+ const double* x1,
+ const double* x2,
+ const double* x3,
+ const double* x4,
+ const double* x5,
+ double* residuals) const {
+ return functor_(x0, x1, x2, x3, x4, x5, 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 {
+ return functor_(x0, x1, x2, x3, x4, x5, x6, 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 {
+ return functor_(x0, x1, x2, x3, x4, x5, x6, x7, 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 {
+ return functor_(x0, x1, x2, x3, x4, x5, x6, x7, x8, 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 {
+ return functor_(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, residuals);
+ }
+
+ template <typename T>
+ bool operator()(const T* x0, T* residuals) const {
+ return functor_(x0, residuals);
+ }
+
+ template <typename T>
+ bool operator()(const T* x0,
+ const T* x1,
+ T* residuals) const {
+ return functor_(x0, x1, residuals);
+ }
+
+ template <typename T>
+ bool operator()(const T* x0,
+ const T* x1,
+ const T* x2,
+ T* residuals) const {
+ return functor_(x0, x1, x2, residuals);
+ }
+
+ template <typename T>
+ bool operator()(const T* x0,
+ const T* x1,
+ const T* x2,
+ const T* x3,
+ T* residuals) const {
+ return functor_(x0, x1, x2, x3, residuals);
+ }
+
+ template <typename T>
+ bool operator()(const T* x0,
+ const T* x1,
+ const T* x2,
+ const T* x3,
+ const T* x4,
+ T* residuals) const {
+ return functor_(x0, x1, x2, x3, x4, residuals);
+ }
+
+ template <typename T>
+ bool operator()(const T* x0,
+ const T* x1,
+ const T* x2,
+ const T* x3,
+ const T* x4,
+ const T* x5,
+ T* residuals) const {
+ return functor_(x0, x1, x2, x3, x4, x5, residuals);
+ }
+
+ template <typename T>
+ bool operator()(const T* x0,
+ const T* x1,
+ const T* x2,
+ const T* x3,
+ const T* x4,
+ const T* x5,
+ const T* x6,
+ T* residuals) const {
+ return functor_(x0, x1, x2, x3, x4, x5, x6, residuals);
+ }
+
+ template <typename T>
+ bool operator()(const T* x0,
+ const T* x1,
+ const T* x2,
+ const T* x3,
+ const T* x4,
+ const T* x5,
+ const T* x6,
+ const T* x7,
+ T* residuals) const {
+ return functor_(x0, x1, x2, x3, x4, x5, x6, x7, residuals);
+ }
+
+ template <typename T>
+ bool operator()(const T* x0,
+ const T* x1,
+ const T* x2,
+ const T* x3,
+ const T* x4,
+ const T* x5,
+ const T* x6,
+ const T* x7,
+ const T* x8,
+ T* residuals) const {
+ return functor_(x0, x1, x2, x3, x4, x5, x6, x7, x8, residuals);
+ }
+
+ template <typename T>
+ bool operator()(const T* x0,
+ const T* x1,
+ const T* x2,
+ const T* x3,
+ const T* x4,
+ const T* x5,
+ const T* x6,
+ const T* x7,
+ const T* x8,
+ const T* x9,
+ T* residuals) const {
+ return functor_(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, residuals);
+ }
+
+
+ private:
+ CostFunctionToFunctor<kNumResiduals,
+ N0, N1, N2, N3, N4,
+ N5, N6, N7, N8, N9> functor_;
+};
+
+} // namespace ceres
+
+#endif // CERES_PUBLIC_NUMERIC_DIFF_FUNCTOR_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
new file mode 100644
index 00000000000..e373d35b9d7
--- /dev/null
+++ b/extern/libmv/third_party/ceres/include/ceres/ordered_groups.h
@@ -0,0 +1,176 @@
+// 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 "ceres/internal/port.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. If the element
+ // is not a member of any group, calling this method will result in
+ // a crash.
+ //
+ // 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;
+ }
+
+ // 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();
+ }
+
+ const map<int, set<T> >& group_to_elements() const {
+ return group_to_elements_;
+ }
+
+ 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
index 2b08c6723e8..bccb329dc55 100644
--- a/extern/libmv/third_party/ceres/include/ceres/problem.h
+++ b/extern/libmv/third_party/ceres/include/ceres/problem.h
@@ -39,11 +39,12 @@
#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 "glog/logging.h"
+
namespace ceres {
@@ -51,6 +52,7 @@ class CostFunction;
class LossFunction;
class LocalParameterization;
class Solver;
+struct CRSMatrix;
namespace internal {
class Preprocessor;
@@ -59,10 +61,9 @@ class ParameterBlock;
class ResidualBlock;
} // namespace internal
-// A ResidualBlockId is a handle clients can use to delete residual
-// blocks after creating them. They are opaque for any purposes other
-// than that.
-typedef const internal::ResidualBlock* ResidualBlockId;
+// 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
@@ -122,7 +123,9 @@ class Problem {
Options()
: cost_function_ownership(TAKE_OWNERSHIP),
loss_function_ownership(TAKE_OWNERSHIP),
- local_parameterization_ownership(TAKE_OWNERSHIP) {}
+ local_parameterization_ownership(TAKE_OWNERSHIP),
+ enable_fast_parameter_block_removal(false),
+ disable_all_safety_checks(false) {}
// These flags control whether the Problem object owns the cost
// functions, loss functions, and parameterizations passed into
@@ -134,6 +137,29 @@ class Problem {
Ownership cost_function_ownership;
Ownership loss_function_ownership;
Ownership local_parameterization_ownership;
+
+ // If true, trades memory for a faster RemoveParameterBlock() operation.
+ //
+ // RemoveParameterBlock() takes time proportional to the size of the entire
+ // Problem. If you only remove parameter blocks from the Problem
+ // occassionaly, this may be acceptable. However, if you are modifying the
+ // Problem frequently, and have memory to spare, then flip this switch to
+ // make RemoveParameterBlock() take time proportional to the number of
+ // residual blocks that depend on it. The increase in memory usage is an
+ // additonal hash set per parameter block containing all the residuals that
+ // depend on the parameter block.
+ bool enable_fast_parameter_block_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
@@ -208,6 +234,27 @@ class Problem {
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
@@ -223,6 +270,33 @@ class Problem {
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_parameter_block_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);
@@ -254,6 +328,76 @@ class Problem {
// sizes of all of the residual blocks.
int NumResiduals() const;
+ // Options struct to control Problem::Evaluate.
+ struct EvaluateOptions {
+ EvaluateOptions()
+ : 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 parmeter
+ // 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;
+ 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.Add(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 vecto (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;
internal::scoped_ptr<internal::ProblemImpl> problem_impl_;
diff --git a/extern/libmv/third_party/ceres/include/ceres/rotation.h b/extern/libmv/third_party/ceres/include/ceres/rotation.h
index 0d8a390d5d1..ffac4f1dc0c 100644
--- a/extern/libmv/third_party/ceres/include/ceres/rotation.h
+++ b/extern/libmv/third_party/ceres/include/ceres/rotation.h
@@ -51,6 +51,31 @@
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,
@@ -73,9 +98,20 @@ void QuaternionToAngleAxis(T const* quaternion, T* angle_axis);
// axis-angle rotation representations. Templated for use with
// autodifferentiation.
template <typename T>
-void RotationMatrixToAngleAxis(T const * R, T * angle_axis);
+void RotationMatrixToAngleAxis(T const* 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(T const * angle_axis, T * R);
+void AngleAxisToRotationMatrix(T const* angle_axis, T* R);
+
+template <typename T, int row_stride, int col_stride>
+void AngleAxisToRotationMatrix(
+ T const* 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.
@@ -86,6 +122,11 @@ void AngleAxisToRotationMatrix(T const * angle_axis, T * R);
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
@@ -108,11 +149,21 @@ void EulerAnglesToRotationMatrix(const T* euler, int row_stride, T* R);
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
@@ -146,6 +197,28 @@ 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];
@@ -228,17 +301,24 @@ inline void QuaternionToAngleAxis(const T* quaternion, T* angle_axis) {
// 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[5] - R[7];
- angle_axis[1] = R[6] - R[2];
- angle_axis[2] = R[1] - R[3];
+ 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] + R[4] + R[8] - kOne) / kTwo,
+ T costheta = std::min(std::max((R(0, 0) + R(1, 1) + R(2, 2) - kOne) / kTwo,
T(-1.0)),
kOne);
@@ -296,7 +376,7 @@ inline void RotationMatrixToAngleAxis(const T * R, T * angle_axis) {
// 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*4] - costheta) * inv_one_minus_costheta);
+ 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];
@@ -306,6 +386,13 @@ inline void RotationMatrixToAngleAxis(const T * R, T * angle_axis) {
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 > 0.0) {
@@ -320,33 +407,41 @@ inline void AngleAxisToRotationMatrix(const T * angle_axis, T * R) {
const T costheta = cos(theta);
const T sintheta = sin(theta);
- R[0] = costheta + wx*wx*(kOne - costheta);
- R[1] = wz*sintheta + wx*wy*(kOne - costheta);
- R[2] = -wy*sintheta + wx*wz*(kOne - costheta);
- R[3] = wx*wy*(kOne - costheta) - wz*sintheta;
- R[4] = costheta + wy*wy*(kOne - costheta);
- R[5] = wx*sintheta + wy*wz*(kOne - costheta);
- R[6] = wy*sintheta + wx*wz*(kOne - costheta);
- R[7] = -wx*sintheta + wy*wz*(kOne - costheta);
- R[8] = costheta + wz*wz*(kOne - costheta);
+ 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 {
// At zero, we switch to using the first order Taylor expansion.
- R[0] = kOne;
- R[1] = -angle_axis[2];
- R[2] = angle_axis[1];
- R[3] = angle_axis[2];
- R[4] = kOne;
- R[5] = -angle_axis[0];
- R[6] = -angle_axis[1];
- R[7] = angle_axis[0];
- R[8] = kOne;
+ 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,
+ 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);
@@ -361,26 +456,28 @@ inline void EulerAnglesToRotationMatrix(const T* euler,
const T c3 = cos(pitch);
const T s3 = sin(pitch);
- // Rows of the rotation matrix.
- T* R1 = R;
- T* R2 = R1 + row_stride;
- T* R3 = R2 + row_stride;
-
- R1[0] = c1*c2;
- R1[1] = -s1*c3 + c1*s2*s3;
- R1[2] = s1*s3 + c1*s2*c3;
+ R(0, 0) = c1*c2;
+ R(0, 1) = -s1*c3 + c1*s2*s3;
+ R(0, 2) = s1*s3 + c1*s2*c3;
- R2[0] = s1*c2;
- R2[1] = c1*c3 + s1*s2*s3;
- R2[2] = -c1*s3 + s1*s2*c3;
+ R(1, 0) = s1*c2;
+ R(1, 1) = c1*c3 + s1*s2*s3;
+ R(1, 2) = -c1*s3 + s1*s2*c3;
- R3[0] = -s2;
- R3[1] = c2*s3;
- R3[2] = c2*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];
@@ -399,21 +496,29 @@ void QuaternionToScaledRotation(const T q[4], T R[3 * 3]) {
T cd = c * d;
T dd = d * d;
- R[0] = aa + bb - cc - dd; R[1] = T(2) * (bc - ad); R[2] = T(2) * (ac + bd); // NOLINT
- R[3] = T(2) * (ad + bc); R[4] = aa - bb + cc - dd; R[5] = T(2) * (cd - ab); // NOLINT
- R[6] = T(2) * (bd - ac); R[7] = T(2) * (ab + cd); R[8] = aa - bb - cc + dd; // NOLINT
+ 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 < 9; ++i) {
- R[i] *= normalizer;
+ for (int i = 0; i < 3; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ R(i, j) *= normalizer;
+ }
}
}
@@ -433,7 +538,6 @@ void UnitQuaternionRotatePoint(const T q[4], const T pt[3], T result[3]) {
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).
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
index 2894a9fba5c..6bfc1af31a2 100644
--- a/extern/libmv/third_party/ceres/include/ceres/sized_cost_function.h
+++ b/extern/libmv/third_party/ceres/include/ceres/sized_cost_function.h
@@ -45,25 +45,29 @@
namespace ceres {
template<int kNumResiduals,
- int N0 = 0, int N1 = 0, int N2 = 0, int N3 = 0, int N4 = 0, int N5 = 0>
+ 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() {
- // Sanity checking.
CHECK(kNumResiduals > 0 || kNumResiduals == DYNAMIC)
<< "Cost functions must have at least one residual block.";
- CHECK_GT(N0, 0)
- << "Cost functions must have at least one parameter block.";
- CHECK((!N1 && !N2 && !N3 && !N4 && !N5) ||
- ((N1 > 0) && !N2 && !N3 && !N4 && !N5) ||
- ((N1 > 0) && (N2 > 0) && !N3 && !N4 && !N5) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && !N4 && !N5) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && !N5) ||
- ((N1 > 0) && (N2 > 0) && (N3 > 0) && (N4 > 0) && (N5 > 0)))
+ // 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;
+ << N3 << ", " << N4 << ", " << N5 << ", " << N6 << ", " << N7 << ", "
+ << N8 << ", " << N9;
set_num_residuals(kNumResiduals);
@@ -75,6 +79,10 @@ class SizedCostFunction : public CostFunction {
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
}
diff --git a/extern/libmv/third_party/ceres/include/ceres/solver.h b/extern/libmv/third_party/ceres/include/ceres/solver.h
index 31d5e8d7987..122870c86c8 100644
--- a/extern/libmv/third_party/ceres/include/ceres/solver.h
+++ b/extern/libmv/third_party/ceres/include/ceres/solver.h
@@ -38,6 +38,7 @@
#include "ceres/internal/macros.h"
#include "ceres/internal/port.h"
#include "ceres/iteration_callback.h"
+#include "ceres/ordered_groups.h"
#include "ceres/types.h"
namespace ceres {
@@ -57,6 +58,11 @@ class Solver {
struct Options {
// Default constructor that sets up a generic sparse problem.
Options() {
+ minimizer_type = TRUST_REGION;
+ line_search_direction_type = LBFGS;
+ line_search_type = ARMIJO;
+ nonlinear_conjugate_gradient_type = FLETCHER_REEVES;
+ max_lbfgs_rank = 20;
trust_region_strategy_type = LEVENBERG_MARQUARDT;
dogleg_type = TRADITIONAL_DOGLEG;
use_nonmonotonic_steps = false;
@@ -89,27 +95,21 @@ class Solver {
#endif
num_linear_solver_threads = 1;
- num_eliminate_blocks = 0;
- ordering_type = NATURAL;
#if defined(CERES_NO_SUITESPARSE)
use_block_amd = false;
#else
use_block_amd = true;
#endif
-
+ linear_solver_ordering = NULL;
+ use_inner_iterations = false;
+ inner_iteration_ordering = NULL;
linear_solver_min_num_iterations = 1;
linear_solver_max_num_iterations = 500;
eta = 1e-1;
jacobi_scaling = true;
logging_type = PER_MINIMIZER_ITERATION;
minimizer_progress_to_stdout = false;
- return_initial_residuals = false;
- return_initial_gradient = false;
- return_initial_jacobian = false;
- return_final_residuals = false;
- return_final_gradient = false;
- return_final_jacobian = false;
lsqp_dump_directory = "/tmp";
lsqp_dump_format_type = TEXTFILE;
check_gradients = false;
@@ -118,8 +118,64 @@ class Solver {
update_state_every_iteration = false;
}
+ ~Options();
// 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;
+
TrustRegionStrategyType trust_region_strategy_type;
// Type of dogleg strategy to use.
@@ -229,29 +285,76 @@ class Solver {
// using this setting.
int num_linear_solver_threads;
- // For Schur reduction based methods, the first 0 to num blocks are
- // eliminated using the Schur reduction. For example, when solving
- // traditional structure from motion problems where the parameters are in
- // two classes (cameras and points) then num_eliminate_blocks would be the
- // number of points.
- //
- // This parameter is used in conjunction with the ordering.
- // Applies to: Preprocessor and linear least squares solver.
- int num_eliminate_blocks;
-
- // Internally Ceres reorders the parameter blocks to help the
- // various linear solvers. This parameter allows the user to
- // influence the re-ordering strategy used. For structure from
- // motion problems use SCHUR, for other problems NATURAL (default)
- // is a good choice. In case you wish to specify your own ordering
- // scheme, for example in conjunction with num_eliminate_blocks,
- // use USER.
- OrderingType ordering_type;
-
- // The ordering of the parameter blocks. The solver pays attention
- // to it if the ordering_type is set to USER and the vector is
- // non-empty.
- vector<double*> ordering;
+ // 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.
+ //
+ // Once assigned, Solver::Options owns this pointer and will
+ // deallocate the memory when destroyed.
+ ParameterBlockOrdering* linear_solver_ordering;
// By virtue of the modeling layer in Ceres being block oriented,
// all the matrices used by Ceres are also block oriented. When
@@ -267,6 +370,77 @@ class Solver {
// sparse_linear_algebra_library = SUITE_SPARSE.
bool use_block_amd;
+ // 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.
+ ParameterBlockOrdering* inner_iteration_ordering;
+
// Minimum number of iterations for which the linear solver should
// run, even if the convergence criterion is satisfied.
int linear_solver_min_num_iterations;
@@ -301,14 +475,6 @@ class Solver {
// is sent to STDOUT.
bool minimizer_progress_to_stdout;
- bool return_initial_residuals;
- bool return_initial_gradient;
- bool return_initial_jacobian;
-
- bool return_final_residuals;
- bool return_final_gradient;
- bool return_final_jacobian;
-
// List of iterations at which the optimizer should dump the
// linear least squares problem to disk. Useful for testing and
// benchmarking. If empty (default), no problems are dumped.
@@ -398,6 +564,8 @@ class Solver {
string FullReport() const;
// Minimizer summary -------------------------------------------------
+ MinimizerType minimizer_type;
+
SolverTerminationType termination_type;
// If the solver did not run, or there was a failure, a
@@ -414,54 +582,6 @@ class Solver {
// blocks that they depend on were fixed.
double fixed_cost;
- // Vectors of residuals before and after the optimization. The
- // entries of these vectors are in the order in which
- // ResidualBlocks were added to the Problem object.
- //
- // Whether the residual vectors are populated with values is
- // controlled by Solver::Options::return_initial_residuals and
- // Solver::Options::return_final_residuals respectively.
- vector<double> initial_residuals;
- vector<double> final_residuals;
-
- // Gradient vectors, before and after the optimization. The rows
- // are in the same order in which the ParameterBlocks were added
- // to the Problem object.
- //
- // NOTE: Since AddResidualBlock adds ParameterBlocks to the
- // Problem automatically if they do not already exist, if you wish
- // to have explicit control over the ordering of the vectors, then
- // use Problem::AddParameterBlock to explicitly add the
- // ParameterBlocks in the order desired.
- //
- // Whether the vectors are populated with values is controlled by
- // Solver::Options::return_initial_gradient and
- // Solver::Options::return_final_gradient respectively.
- vector<double> initial_gradient;
- vector<double> final_gradient;
-
- // Jacobian matrices before and after the optimization. The rows
- // of these matrices are in the same order in which the
- // ResidualBlocks were added to the Problem object. The columns
- // are in the same order in which the ParameterBlocks were added
- // to the Problem object.
- //
- // NOTE: Since AddResidualBlock adds ParameterBlocks to the
- // Problem automatically if they do not already exist, if you wish
- // to have explicit control over the column ordering of the
- // matrix, then use Problem::AddParameterBlock to explicitly add
- // the ParameterBlocks in the order desired.
- //
- // The Jacobian matrices are stored as compressed row sparse
- // matrices. Please see ceres/crs_matrix.h for more details of the
- // format.
- //
- // Whether the Jacboan matrices are populated with values is
- // controlled by Solver::Options::return_initial_jacobian and
- // Solver::Options::return_final_jacobian respectively.
- CRSMatrix initial_jacobian;
- CRSMatrix final_jacobian;
-
vector<IterationSummary> iterations;
int num_successful_steps;
@@ -484,6 +604,10 @@ class Solver {
// Some total of all time spent inside Ceres when Solve is called.
double total_time_in_seconds;
+ double linear_solver_time_in_seconds;
+ double residual_evaluation_time_in_seconds;
+ double jacobian_evaluation_time_in_seconds;
+
// Preprocessor summary.
int num_parameter_blocks;
int num_parameters;
@@ -507,12 +631,23 @@ class Solver {
LinearSolverType linear_solver_type_given;
LinearSolverType linear_solver_type_used;
+ vector<int> linear_solver_ordering_given;
+ vector<int> linear_solver_ordering_used;
+
PreconditionerType preconditioner_type;
- OrderingType ordering_type;
TrustRegionStrategyType trust_region_strategy_type;
DoglegType dogleg_type;
+ bool inner_iterations;
+
SparseLinearAlgebraLibraryType sparse_linear_algebra_library;
+
+ LineSearchDirectionType line_search_direction_type;
+ LineSearchType line_search_type;
+ int max_lbfgs_rank;
+
+ vector<int> inner_iteration_ordering_given;
+ vector<int> inner_iteration_ordering_used;
};
// Once a least squares problem has been built, this function takes
diff --git a/extern/libmv/third_party/ceres/include/ceres/types.h b/extern/libmv/third_party/ceres/include/ceres/types.h
index 3980885b53c..5512340f7b3 100644
--- a/extern/libmv/third_party/ceres/include/ceres/types.h
+++ b/extern/libmv/third_party/ceres/include/ceres/types.h
@@ -37,6 +37,8 @@
#ifndef CERES_PUBLIC_TYPES_H_
#define CERES_PUBLIC_TYPES_H_
+#include "ceres/internal/port.h"
+
namespace ceres {
// Basic integer types. These typedefs are in the Ceres namespace to avoid
@@ -99,8 +101,7 @@ enum PreconditionerType {
JACOBI,
// Block diagonal of the Schur complement. This preconditioner may
- // only be used with the ITERATIVE_SCHUR solver. Requires
- // SuiteSparse/CHOLMOD.
+ // only be used with the ITERATIVE_SCHUR solver.
SCHUR_JACOBI,
// Visibility clustering based preconditioners.
@@ -143,18 +144,6 @@ enum LinearSolverTerminationType {
FAILURE
};
-enum OrderingType {
- // The order in which the parameter blocks were defined.
- NATURAL,
-
- // Use the ordering specificed in the vector ordering.
- USER,
-
- // Automatically figure out the best ordering to use the schur
- // complement based solver.
- SCHUR
-};
-
// Logging options
// The options get progressively noisier.
enum LoggingType {
@@ -162,6 +151,55 @@ enum LoggingType {
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,
+
+ // A limited memory approximation to the inverse Hessian is
+ // maintained and used to compute a quasi-Newton step.
+ //
+ // For more details 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.
+ LBFGS,
+};
+
+// 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_RIBIRERE,
+ HESTENES_STIEFEL,
+};
+
+enum LineSearchType {
+ // Backtracking line search with polynomial interpolation or
+ // bisection.
+ ARMIJO,
+};
+
// Ceres supports different strategies for computing the trust region
// step.
enum TrustRegionStrategyType {
@@ -296,18 +334,54 @@ enum DimensionType {
DYNAMIC = -1
};
+enum NumericDiffMethod {
+ CENTRAL,
+ FORWARD
+};
+
const char* LinearSolverTypeToString(LinearSolverType type);
+bool StringToLinearSolverType(string value, LinearSolverType* type);
+
const char* PreconditionerTypeToString(PreconditionerType type);
+bool StringToPreconditionerType(string value, PreconditionerType* type);
+
const char* SparseLinearAlgebraLibraryTypeToString(
SparseLinearAlgebraLibraryType type);
+bool StringToSparseLinearAlgebraLibraryType(
+ string value,
+ SparseLinearAlgebraLibraryType* type);
+
+const char* TrustRegionStrategyTypeToString(TrustRegionStrategyType type);
+bool StringToTrustRegionStrategyType(string value,
+ TrustRegionStrategyType* type);
+
+const char* DoglegTypeToString(DoglegType type);
+bool StringToDoglegType(string value, DoglegType* type);
+
+const char* MinimizerTypeToString(MinimizerType type);
+bool StringToMinimizerType(string value, MinimizerType* type);
+
+const char* LineSearchDirectionTypeToString(LineSearchDirectionType type);
+bool StringToLineSearchDirectionType(string value,
+ LineSearchDirectionType* type);
+
+const char* LineSearchTypeToString(LineSearchType type);
+bool StringToLineSearchType(string value, LineSearchType* type);
+
+const char* NonlinearConjugateGradientTypeToString(
+ NonlinearConjugateGradientType type);
+bool StringToNonlinearConjugateGradientType(
+ string value, NonlinearConjugateGradientType* type);
+
const char* LinearSolverTerminationTypeToString(
LinearSolverTerminationType type);
-const char* OrderingTypeToString(OrderingType type);
+
const char* SolverTerminationTypeToString(SolverTerminationType type);
-const char* SparseLinearAlgebraLibraryTypeToString(
- SparseLinearAlgebraLibraryType type);
-const char* TrustRegionStrategyTypeToString( TrustRegionStrategyType type);
+
bool IsSchurType(LinearSolverType type);
+bool IsSparseLinearAlgebraLibraryTypeAvailable(
+ SparseLinearAlgebraLibraryType type);
+
} // 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
index 99cc8d8ebbf..742f439d886 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/array_utils.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/array_utils.h
@@ -28,7 +28,7 @@
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
//
-// Utility routines for validating arrays.
+// Utility routines for validating arrays.
//
// These are useful for detecting two common class of errors.
//
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
index 474c37f7ca4..1d5f9d77ab0 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc
@@ -40,10 +40,10 @@
namespace ceres {
namespace internal {
-BlockJacobiPreconditioner::BlockJacobiPreconditioner(const LinearOperator& A)
+BlockJacobiPreconditioner::BlockJacobiPreconditioner(
+ const BlockSparseMatrixBase& A)
: num_rows_(A.num_rows()),
- block_structure_(
- *(down_cast<const BlockSparseMatrix*>(&A)->block_structure())) {
+ block_structure_(*A.block_structure()) {
// Calculate the amount of storage needed.
int storage_needed = 0;
for (int c = 0; c < block_structure_.cols.size(); ++c) {
@@ -64,11 +64,10 @@ BlockJacobiPreconditioner::BlockJacobiPreconditioner(const LinearOperator& A)
}
}
-BlockJacobiPreconditioner::~BlockJacobiPreconditioner() {
-}
+BlockJacobiPreconditioner::~BlockJacobiPreconditioner() {}
-void BlockJacobiPreconditioner::Update(const LinearOperator& matrix, const double* D) {
- const BlockSparseMatrix& A = *(down_cast<const BlockSparseMatrix*>(&matrix));
+bool BlockJacobiPreconditioner::Update(const BlockSparseMatrixBase& A,
+ const double* D) {
const CompressedRowBlockStructure* bs = A.block_structure();
// Compute the diagonal blocks by block inner products.
@@ -107,16 +106,19 @@ void BlockJacobiPreconditioner::Update(const LinearOperator& matrix, const doubl
MatrixRef block(blocks_[c], size, size);
if (D != NULL) {
- block.diagonal() += ConstVectorRef(D + position, size).array().square().matrix();
+ block.diagonal() +=
+ ConstVectorRef(D + position, size).array().square().matrix();
}
block = block.selfadjointView<Eigen::Upper>()
.ldlt()
.solve(Matrix::Identity(size, size));
}
+ return true;
}
-void BlockJacobiPreconditioner::RightMultiply(const double* x, double* y) const {
+void BlockJacobiPreconditioner::RightMultiply(const double* x,
+ double* y) const {
for (int c = 0; c < block_structure_.cols.size(); ++c) {
const int size = block_structure_.cols[c].size;
const int position = block_structure_.cols[c].position;
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
index 91cfeddb688..ed5eebc8dc6 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h
@@ -32,38 +32,33 @@
#define CERES_INTERNAL_BLOCK_JACOBI_PRECONDITIONER_H_
#include <vector>
-#include "ceres/linear_operator.h"
+#include "ceres/preconditioner.h"
namespace ceres {
namespace internal {
-class CompressedRowBlockStructure;
+class BlockSparseMatrixBase;
+struct CompressedRowBlockStructure;
class LinearOperator;
-class SparseMatrix;
-// 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 as the linear operator "A" to the
-// constructor. This fixes the sparsity pattern to the pattern of the matrix
-// A^TA.
+// 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 LinearOperator {
+class BlockJacobiPreconditioner : public Preconditioner {
public:
// A must remain valid while the BlockJacobiPreconditioner is.
- BlockJacobiPreconditioner(const LinearOperator& A);
+ explicit BlockJacobiPreconditioner(const BlockSparseMatrixBase& A);
virtual ~BlockJacobiPreconditioner();
- // Update the preconditioner with the values found in A. The sparsity pattern
- // must match that of the A passed to the constructor. D is a vector that
- // must have the same number of rows as A, and is applied as a diagonal in
- // addition to the block diagonals of A.
- void Update(const LinearOperator& A, const double* D);
-
- // LinearOperator interface.
+ // Preconditioner interface
+ virtual bool Update(const BlockSparseMatrixBase& A, const double* D);
virtual void RightMultiply(const double* x, double* y) const;
virtual void LeftMultiply(const double* x, double* y) const;
virtual int num_rows() const { return num_rows_; }
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
index 0f95e8932b8..aedfc745f22 100644
--- 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
@@ -28,12 +28,12 @@
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
-#include "glog/logging.h"
#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 {
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
index 9ed62ce948b..f789436364a 100644
--- 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
@@ -28,7 +28,6 @@
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
-#include "glog/logging.h"
#include "ceres/block_random_access_sparse_matrix.h"
#include <algorithm>
@@ -40,6 +39,7 @@
#include "ceres/mutex.h"
#include "ceres/triplet_sparse_matrix.h"
#include "ceres/types.h"
+#include "glog/logging.h"
namespace ceres {
namespace internal {
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
index 2d1eb403995..5f8e4e3e5dd 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/canonical_views_clustering.h
@@ -43,16 +43,16 @@
#include <vector>
-#include <glog/logging.h>
#include "ceres/collections_port.h"
#include "ceres/graph.h"
-#include "ceres/map_util.h"
#include "ceres/internal/macros.h"
+#include "ceres/map_util.h"
+#include "glog/logging.h"
namespace ceres {
namespace internal {
-class CanonicalViewsClusteringOptions;
+struct CanonicalViewsClusteringOptions;
// Compute a partitioning of the vertices of the graph using the
// canonical views clustering algorithm.
diff --git a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc
index ccc8026f9f7..e2e799fe607 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.cc
@@ -30,25 +30,28 @@
#include "ceres/cgnr_solver.h"
-#include "glog/logging.h"
-#include "ceres/linear_solver.h"
+#include "ceres/block_jacobi_preconditioner.h"
#include "ceres/cgnr_linear_operator.h"
#include "ceres/conjugate_gradients_solver.h"
-#include "ceres/block_jacobi_preconditioner.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),
- jacobi_preconditioner_(NULL) {
+ preconditioner_(NULL) {
}
-LinearSolver::Summary CgnrSolver::Solve(
- LinearOperator* A,
+LinearSolver::Summary CgnrSolver::SolveImpl(
+ BlockSparseMatrixBase* A,
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double* x) {
+ EventLogger event_logger("CgnrSolver::Solve");
+
// Form z = Atb.
scoped_array<double> z(new double[A->num_cols()]);
std::fill(z.get(), z.get() + A->num_cols(), 0.0);
@@ -57,11 +60,11 @@ LinearSolver::Summary CgnrSolver::Solve(
// Precondition if necessary.
LinearSolver::PerSolveOptions cg_per_solve_options = per_solve_options;
if (options_.preconditioner_type == JACOBI) {
- if (jacobi_preconditioner_.get() == NULL) {
- jacobi_preconditioner_.reset(new BlockJacobiPreconditioner(*A));
+ if (preconditioner_.get() == NULL) {
+ preconditioner_.reset(new BlockJacobiPreconditioner(*A));
}
- jacobi_preconditioner_->Update(*A, per_solve_options.D);
- cg_per_solve_options.preconditioner = jacobi_preconditioner_.get();
+ preconditioner_->Update(*A, per_solve_options.D);
+ cg_per_solve_options.preconditioner = preconditioner_.get();
} else if (options_.preconditioner_type != IDENTITY) {
LOG(FATAL) << "CGNR only supports IDENTITY and JACOBI preconditioners.";
}
@@ -69,11 +72,14 @@ LinearSolver::Summary CgnrSolver::Solve(
// Solve (AtA + DtD)x = z (= Atb).
std::fill(x, x + A->num_cols(), 0.0);
CgnrLinearOperator lhs(*A, per_solve_options.D);
+ event_logger.AddEvent("Setup");
+
ConjugateGradientsSolver conjugate_gradient_solver(options_);
- return conjugate_gradient_solver.Solve(&lhs,
- z.get(),
- cg_per_solve_options,
- x);
+ LinearSolver::Summary summary =
+ conjugate_gradient_solver.Solve(&lhs, z.get(), cg_per_solve_options, x);
+ event_logger.AddEvent("Solve");
+
+ return summary;
}
} // namespace internal
diff --git a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h b/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h
index 877b4c4ceea..d560a9de58d 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/cgnr_solver.h
@@ -37,6 +37,8 @@
namespace ceres {
namespace internal {
+class Preconditioner;
+
class BlockJacobiPreconditioner;
// A conjugate gradients on the normal equations solver. This directly solves
@@ -46,17 +48,18 @@ class BlockJacobiPreconditioner;
//
// as required for solving for x in the least squares sense. Currently only
// block diagonal preconditioning is supported.
-class CgnrSolver : public LinearSolver {
+class CgnrSolver : public BlockSparseMatrixBaseSolver {
public:
explicit CgnrSolver(const LinearSolver::Options& options);
- virtual Summary Solve(LinearOperator* A,
- const double* b,
- const LinearSolver::PerSolveOptions& per_solve_options,
- double* x);
+ virtual Summary SolveImpl(
+ BlockSparseMatrixBase* A,
+ const double* b,
+ const LinearSolver::PerSolveOptions& per_solve_options,
+ double* x);
private:
const LinearSolver::Options options_;
- scoped_ptr<BlockJacobiPreconditioner> jacobi_preconditioner_;
+ scoped_ptr<Preconditioner> preconditioner_;
CERES_DISALLOW_COPY_AND_ASSIGN(CgnrSolver);
};
diff --git a/extern/libmv/third_party/ceres/internal/ceres/collections_port.h b/extern/libmv/third_party/ceres/internal/ceres/collections_port.h
index c2fce9033cd..715c975e00e 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/collections_port.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/collections_port.h
@@ -37,7 +37,7 @@
# include <map>
# include <set>
#else
-# if defined(_MSC_VER) && _MSC_VER <= 1600
+# if defined(_MSC_VER)
# include <unordered_map>
# include <unordered_set>
# else
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
index 912c4845441..bbadb772805 100644
--- 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
@@ -135,7 +135,8 @@ SparseMatrix* CompressedRowJacobianWriter::CreateJacobian() const {
// Populate the row and column block vectors for use by block
// oriented ordering algorithms. This is useful when
// Solver::Options::use_block_amd = true.
- const vector<ParameterBlock*>& parameter_blocks = program_->parameter_blocks();
+ 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) {
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
index 6a9d82842e5..c9c904bf63c 100644
--- 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
@@ -32,17 +32,18 @@
#define CERES_INTERNAL_COMPRESSED_ROW_SPARSE_MATRIX_H_
#include <vector>
-#include <glog/logging.h>
-#include "ceres/sparse_matrix.h"
-#include "ceres/triplet_sparse_matrix.h"
+
#include "ceres/internal/eigen.h"
#include "ceres/internal/macros.h"
#include "ceres/internal/port.h"
+#include "ceres/sparse_matrix.h"
+#include "ceres/triplet_sparse_matrix.h"
#include "ceres/types.h"
+#include "glog/logging.h"
namespace ceres {
-class CRSMatrix;
+struct CRSMatrix;
namespace internal {
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
new file mode 100644
index 00000000000..c4da987919a
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc
@@ -0,0 +1,236 @@
+// 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/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/ordered_groups.h"
+#include "ceres/parameter_block.h"
+#include "ceres/problem_impl.h"
+#include "ceres/program.h"
+#include "ceres/residual_block.h"
+#include "ceres/solver.h"
+#include "ceres/solver_impl.h"
+#include "ceres/trust_region_minimizer.h"
+#include "ceres/trust_region_strategy.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) {
+ // No point paying the price for an OpemMP call if the set if of
+ // size zero.
+ if (independent_set_offsets_[i] == independent_set_offsets_[i + 1]) {
+ continue;
+ }
+
+ // 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(options.num_threads)
+ 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;
+
+ scoped_ptr<Evaluator> evaluator(
+ Evaluator::Create(evaluator_options_, program, &error));
+ CHECK_NOTNULL(evaluator.get());
+
+ scoped_ptr<SparseMatrix> jacobian(evaluator->CreateJacobian());
+ CHECK_NOTNULL(jacobian.get());
+
+ TrustRegionStrategy::Options trs_options;
+ trs_options.linear_solver = linear_solver;
+
+ scoped_ptr<TrustRegionStrategy>trust_region_strategy(
+ CHECK_NOTNULL(TrustRegionStrategy::Create(trs_options)));
+
+ Minimizer::Options minimizer_options;
+ minimizer_options.evaluator = evaluator.get();
+ minimizer_options.jacobian = jacobian.get();
+ minimizer_options.trust_region_strategy = trust_region_strategy.get();
+
+ TrustRegionMinimizer minimizer;
+ minimizer.Minimize(minimizer_options, parameter, summary);
+}
+
+} // 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
new file mode 100644
index 00000000000..3dcf8faee59
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h
@@ -0,0 +1,88 @@
+// 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 <vector>
+
+#include "ceres/evaluator.h"
+#include "ceres/minimizer.h"
+#include "ceres/problem_impl.h"
+#include "ceres/program.h"
+#include "ceres/solver.h"
+
+namespace ceres {
+namespace internal {
+
+// 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);
+
+ 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
index eff4dff8566..c3858abd2f4 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/corrector.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/corrector.cc
@@ -113,12 +113,19 @@ void Corrector::CorrectJacobian(int nrow, int ncol,
double* residuals, double* jacobian) {
DCHECK(residuals != NULL);
DCHECK(jacobian != NULL);
- ConstVectorRef r_ref(residuals, nrow);
- MatrixRef j_ref(jacobian, nrow, ncol);
- // Equation 11 in BANS.
- j_ref = sqrt_rho1_ * (j_ref - alpha_sq_norm_ *
- r_ref * (r_ref.transpose() * j_ref));
+ if (nrow == 1) {
+ // Specialization for the case where the residual is a scalar.
+ VectorRef j_ref(jacobian, ncol);
+ j_ref *= sqrt_rho1_ * (1.0 - alpha_sq_norm_ * pow(*residuals, 2));
+ } else {
+ ConstVectorRef r_ref(residuals, nrow);
+ MatrixRef j_ref(jacobian, nrow, ncol);
+
+ // Equation 11 in BANS.
+ j_ref = sqrt_rho1_ * (j_ref - alpha_sq_norm_ *
+ r_ref * (r_ref.transpose() * j_ref));
+ }
}
} // namespace internal
diff --git a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc
index ca36ce07614..19fa17cc37d 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.cc
@@ -39,7 +39,7 @@
namespace ceres {
namespace internal {
-CXSparse::CXSparse() : scratch_size_(0), scratch_(NULL) {
+CXSparse::CXSparse() : scratch_(NULL), scratch_size_(0) {
}
CXSparse::~CXSparse() {
@@ -116,12 +116,12 @@ cs_di* CXSparse::CreateSparseMatrix(TripletSparseMatrix* tsm) {
return cs_compress(&tsm_wrapper);
}
-void CXSparse::Free(cs_di* factor) {
- cs_free(factor);
+void CXSparse::Free(cs_di* sparse_matrix) {
+ cs_di_spfree(sparse_matrix);
}
-void CXSparse::Free(cs_dis* factor) {
- cs_sfree(factor);
+void CXSparse::Free(cs_dis* symbolic_factorization) {
+ cs_di_sfree(symbolic_factorization);
}
} // namespace internal
diff --git a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h
index d3b64fcd1a5..dd5eadc8da8 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/cxsparse.h
@@ -72,9 +72,8 @@ class CXSparse {
// The returned matrix should be deallocated with Free when not used anymore.
cs_dis* AnalyzeCholesky(cs_di* A);
- // Deallocates the memory of a matrix obtained from AnalyzeCholesky.
- void Free(cs_di* factor);
- void Free(cs_dis* factor);
+ void Free(cs_di* sparse_matrix);
+ void Free(cs_dis* symbolic_factorization);
private:
// Cached scratch space
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
index 1177b83a556..be743a8591c 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_jacobian_writer.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/dense_jacobian_writer.h
@@ -62,7 +62,8 @@ class DenseJacobianWriter {
SparseMatrix* CreateJacobian() const {
return new DenseSparseMatrix(program_->NumResiduals(),
- program_->NumEffectiveParameters());
+ program_->NumEffectiveParameters(),
+ true);
}
void Write(int residual_id,
@@ -87,10 +88,10 @@ class DenseJacobianWriter {
continue;
}
- int parameter_block_size = parameter_block->LocalSize();
- MatrixRef parameter_jacobian(jacobians[j],
- num_residuals,
- parameter_block_size);
+ 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,
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
index f6bb99abf63..a340e1664f0 100644
--- 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
@@ -34,10 +34,11 @@
#include "Eigen/Dense"
#include "ceres/dense_sparse_matrix.h"
-#include "ceres/linear_solver.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/scoped_ptr.h"
+#include "ceres/linear_solver.h"
#include "ceres/types.h"
+#include "ceres/wall_time.h"
namespace ceres {
namespace internal {
@@ -51,6 +52,8 @@ LinearSolver::Summary DenseNormalCholeskySolver::SolveImpl(
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();
@@ -58,6 +61,7 @@ LinearSolver::Summary DenseNormalCholeskySolver::SolveImpl(
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
@@ -73,12 +77,13 @@ LinearSolver::Summary DenseNormalCholeskySolver::SolveImpl(
lhs += D.array().square().matrix().asDiagonal();
}
- VectorRef(x, num_cols) =
- lhs.selfadjointView<Eigen::Upper>().ldlt().solve(rhs);
-
LinearSolver::Summary summary;
summary.num_iterations = 1;
summary.termination_type = TOLERANCE;
+ VectorRef(x, num_cols) =
+ lhs.selfadjointView<Eigen::Upper>().ldlt().solve(rhs);
+ event_logger.AddEvent("Solve");
+
return summary;
}
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
index 2b329ee0e9c..1fb9709b42a 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.cc
@@ -34,10 +34,11 @@
#include "Eigen/Dense"
#include "ceres/dense_sparse_matrix.h"
-#include "ceres/linear_solver.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/scoped_ptr.h"
+#include "ceres/linear_solver.h"
#include "ceres/types.h"
+#include "ceres/wall_time.h"
namespace ceres {
namespace internal {
@@ -50,10 +51,10 @@ LinearSolver::Summary DenseQRSolver::SolveImpl(
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();
- VLOG(2) << "DenseQRSolver: "
- << num_rows << " x " << num_cols << " system.";
if (per_solve_options.D != NULL) {
// Temporarily append a diagonal block to the A matrix, but undo
@@ -62,18 +63,18 @@ LinearSolver::Summary DenseQRSolver::SolveImpl(
}
// rhs = [b;0] to account for the additional rows in the lhs.
- Vector rhs(num_rows + ((per_solve_options.D != NULL) ? num_cols : 0));
- rhs.setZero();
- rhs.head(num_rows) = ConstVectorRef(b, num_rows);
+ 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().colPivHouseholderQr().solve(rhs);
-
- VLOG(3) << "A:\n" << A->matrix();
- VLOG(3) << "x:\n" << VectorRef(x, num_cols);
- VLOG(3) << "b:\n" << rhs;
- VLOG(3) << "error: " << (A->matrix() * VectorRef(x, num_cols) - rhs).norm();
-
+ VectorRef(x, num_cols) = A->matrix().colPivHouseholderQr().solve(rhs_);
+ event_logger.AddEvent("Solve");
if (per_solve_options.D != NULL) {
// Undo the modifications to the matrix A.
@@ -86,6 +87,8 @@ LinearSolver::Summary DenseQRSolver::SolveImpl(
LinearSolver::Summary summary;
summary.num_iterations = 1;
summary.termination_type = TOLERANCE;
+
+ event_logger.AddEvent("TearDown");
return summary;
}
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
index dd683a8c4ea..f78fa72c5f3 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/dense_qr_solver.h
@@ -33,6 +33,7 @@
#define CERES_INTERNAL_DENSE_QR_SOLVER_H_
#include "ceres/linear_solver.h"
+#include "ceres/internal/eigen.h"
#include "ceres/internal/macros.h"
namespace ceres {
@@ -90,6 +91,7 @@ class DenseQRSolver: public DenseSparseMatrixSolver {
double* x);
const LinearSolver::Options options_;
+ Vector rhs_;
CERES_DISALLOW_COPY_AND_ASSIGN(DenseQRSolver);
};
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
index 86730cc101b..978ac6abe15 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.cc
@@ -47,6 +47,20 @@ DenseSparseMatrix::DenseSparseMatrix(int num_rows, int num_cols)
m_.setZero();
}
+DenseSparseMatrix::DenseSparseMatrix(int num_rows,
+ int num_cols,
+ bool reserve_diagonal)
+ : has_diagonal_appended_(false),
+ has_diagonal_reserved_(reserve_diagonal) {
+ // Allocate enough space for the diagonal.
+ if (reserve_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),
@@ -105,7 +119,7 @@ void DenseSparseMatrix::ScaleColumns(const double* scale) {
}
void DenseSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
- *dense_matrix = m_;
+ *dense_matrix = m_.block(0, 0, num_rows(), num_cols());
}
#ifndef CERES_NO_PROTOCOL_BUFFERS
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
index e7ad14d0ee6..1e4d499b631 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/dense_sparse_matrix.h
@@ -57,6 +57,7 @@ class DenseSparseMatrix : public SparseMatrix {
#endif
DenseSparseMatrix(int num_rows, int num_cols);
+ DenseSparseMatrix(int num_rows, int num_cols, bool reserve_diagonal);
virtual ~DenseSparseMatrix() {}
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc
index 668fa54b8b8..a330ad2c7a2 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.cc
@@ -35,7 +35,7 @@
#include "ceres/array_utils.h"
#include "ceres/internal/eigen.h"
#include "ceres/linear_solver.h"
-#include "ceres/polynomial_solver.h"
+#include "ceres/polynomial.h"
#include "ceres/sparse_matrix.h"
#include "ceres/trust_region_strategy.h"
#include "ceres/types.h"
@@ -87,7 +87,7 @@ TrustRegionStrategy::Summary DoglegStrategy::ComputeStep(
// 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_) {
+ switch (dogleg_type_) {
case TRADITIONAL_DOGLEG:
ComputeTraditionalDoglegStep(step);
break;
@@ -135,7 +135,7 @@ TrustRegionStrategy::Summary DoglegStrategy::ComputeStep(
summary.termination_type = linear_solver_summary.termination_type;
if (linear_solver_summary.termination_type != FAILURE) {
- switch(dogleg_type_) {
+ switch (dogleg_type_) {
// Interpolate the Cauchy point and the Gauss-Newton step.
case TRADITIONAL_DOGLEG:
ComputeTraditionalDoglegStep(step);
@@ -415,15 +415,15 @@ Vector DoglegStrategy::MakePolynomialForBoundaryConstrainedProblem() const {
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);
+ 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(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;
@@ -598,7 +598,7 @@ void DoglegStrategy::StepAccepted(double step_quality) {
// 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_ );
+ mu_ = max(min_mu_, 2.0 * mu_ / mu_increase_factor_);
reuse_ = false;
}
diff --git a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h
index bff1689aa4a..7131467d6ce 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/dogleg_strategy.h
@@ -53,8 +53,8 @@ namespace internal {
// This finds the exact optimum over the two-dimensional subspace
// spanned by the two Dogleg vectors.
class DoglegStrategy : public TrustRegionStrategy {
-public:
- DoglegStrategy(const TrustRegionStrategy::Options& options);
+ public:
+ explicit DoglegStrategy(const TrustRegionStrategy::Options& options);
virtual ~DoglegStrategy() {}
// TrustRegionStrategy interface
diff --git a/extern/libmv/third_party/ceres/internal/ceres/evaluator.h b/extern/libmv/third_party/ceres/internal/ceres/evaluator.h
index 6aa30d7b739..14a88188145 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/evaluator.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/evaluator.h
@@ -32,14 +32,17 @@
#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 {
-class CRSMatrix;
+struct CRSMatrix;
namespace internal {
@@ -152,6 +155,18 @@ class Evaluator {
// 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
diff --git a/extern/libmv/third_party/ceres/internal/ceres/execution_summary.h b/extern/libmv/third_party/ceres/internal/ceres/execution_summary.h
new file mode 100644
index 00000000000..29bdc69ecd7
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/execution_summary.h
@@ -0,0 +1,90 @@
+// 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
index 6fe7557246d..5226c85e6ee 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/file.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/file.cc
@@ -30,8 +30,9 @@
//
// Really simple file IO.
+#include "ceres/file.h"
+
#include <cstdio>
-#include "file.h"
#include "glog/logging.h"
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
index 7fb3ed7b3a8..3edf95da6e0 100644
--- 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
@@ -154,8 +154,8 @@ class GradientCheckingCostFunction : public CostFunction {
"Jacobian for " "block %d: (%ld by %ld)) "
"==========\n",
k,
- term_jacobians[k].rows(),
- term_jacobians[k].cols());
+ 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";
diff --git a/extern/libmv/third_party/ceres/internal/ceres/graph.h b/extern/libmv/third_party/ceres/internal/ceres/graph.h
index 2c0f6d28e54..5f92d4d4df2 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/graph.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/graph.h
@@ -32,12 +32,13 @@
#define CERES_INTERNAL_GRAPH_H_
#include <limits>
-#include <glog/logging.h>
+#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 {
@@ -65,6 +66,28 @@ class Graph {
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.
diff --git a/extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h b/extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h
index 3b42d936336..2e6eec0e6d8 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/graph_algorithms.h
@@ -33,10 +33,12 @@
#ifndef CERES_INTERNAL_GRAPH_ALGORITHMS_H_
#define CERES_INTERNAL_GRAPH_ALGORITHMS_H_
+#include <algorithm>
#include <vector>
-#include <glog/logging.h>
+#include <utility>
#include "ceres/collections_port.h"
#include "ceres/graph.h"
+#include "glog/logging.h"
namespace ceres {
namespace internal {
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
index 679c41f2431..cf5562ac771 100644
--- 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
@@ -33,6 +33,7 @@
#include <algorithm>
#include <cstring>
#include <vector>
+
#include "Eigen/Dense"
#include "ceres/block_sparse_matrix.h"
#include "ceres/block_structure.h"
@@ -41,9 +42,12 @@
#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 {
@@ -62,12 +66,14 @@ LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl(
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double* x) {
+ EventLogger event_logger("IterativeSchurComplementSolver::Solve");
+
CHECK_NOTNULL(A->block_structure());
// Initialize a ImplicitSchurComplement object.
if (schur_complement_ == NULL) {
schur_complement_.reset(
- new ImplicitSchurComplement(options_.num_eliminate_blocks,
+ new ImplicitSchurComplement(options_.elimination_groups[0],
options_.preconditioner_type == JACOBI));
}
schur_complement_->Init(*A, per_solve_options.D, b);
@@ -89,44 +95,58 @@ LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl(
cg_per_solve_options.r_tolerance = per_solve_options.r_tolerance;
cg_per_solve_options.q_tolerance = per_solve_options.q_tolerance;
- bool is_preconditioner_good = false;
+ Preconditioner::Options preconditioner_options;
+ preconditioner_options.type = options_.preconditioner_type;
+ preconditioner_options.sparse_linear_algebra_library =
+ options_.sparse_linear_algebra_library;
+ preconditioner_options.use_block_amd = options_.use_block_amd;
+ 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:
- is_preconditioner_good = true;
break;
case JACOBI:
- // We need to strip the constness of the block_diagonal_FtF_inverse
- // matrix here because the only other way to initialize the struct
- // cg_solve_options would be to add a constructor to it. We know
- // that the only method ever called on the preconditioner is the
- // RightMultiply which is a const method so we don't need to worry
- // about the object getting modified.
- cg_per_solve_options.preconditioner =
- const_cast<BlockSparseMatrix*>(
- schur_complement_->block_diagonal_FtF_inverse());
- is_preconditioner_good = true;
+ 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 (visibility_based_preconditioner_.get() == NULL) {
- visibility_based_preconditioner_.reset(
- new VisibilityBasedPreconditioner(*A->block_structure(), options_));
+ if (preconditioner_.get() == NULL) {
+ preconditioner_.reset(
+ new VisibilityBasedPreconditioner(
+ *A->block_structure(), preconditioner_options));
}
- is_preconditioner_good =
- visibility_based_preconditioner_->Update(*A, per_solve_options.D);
- cg_per_solve_options.preconditioner =
- visibility_based_preconditioner_.get();
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 = FAILURE;
- if (is_preconditioner_good) {
+ if (preconditioner_update_was_successful) {
cg_summary = cg_solver.Solve(schur_complement_.get(),
schur_complement_->rhs().data(),
cg_per_solve_options,
@@ -138,6 +158,8 @@ LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl(
}
VLOG(2) << "CG Iterations : " << cg_summary.num_iterations;
+
+ event_logger.AddEvent("Solve");
return cg_summary;
}
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
index cfeb65e1eec..f8abe04c142 100644
--- 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
@@ -39,13 +39,12 @@
namespace ceres {
namespace internal {
-class BlockSparseMatrix;
class BlockSparseMatrixBase;
class ImplicitSchurComplement;
-class VisibilityBasedPreconditioner;
+class Preconditioner;
// This class implements an iterative solver for the linear least
-// squares problems that have a bi-partitte sparsity structure common
+// 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
@@ -70,9 +69,7 @@ class VisibilityBasedPreconditioner;
// "Iterative Methods for Sparse Linear Systems".
class IterativeSchurComplementSolver : public BlockSparseMatrixBaseSolver {
public:
- explicit IterativeSchurComplementSolver(
- const LinearSolver::Options& options);
-
+ explicit IterativeSchurComplementSolver(const LinearSolver::Options& options);
virtual ~IterativeSchurComplementSolver();
private:
@@ -84,8 +81,9 @@ class IterativeSchurComplementSolver : public BlockSparseMatrixBaseSolver {
LinearSolver::Options options_;
scoped_ptr<internal::ImplicitSchurComplement> schur_complement_;
- scoped_ptr<VisibilityBasedPreconditioner> visibility_based_preconditioner_;
+ scoped_ptr<Preconditioner> preconditioner_;
Vector reduced_linear_system_solution_;
+ CERES_DISALLOW_COPY_AND_ASSIGN(IterativeSchurComplementSolver);
};
} // namespace internal
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
index 90c21789797..344e3285422 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h
@@ -43,8 +43,9 @@ namespace internal {
//
// http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf
class LevenbergMarquardtStrategy : public TrustRegionStrategy {
-public:
- LevenbergMarquardtStrategy(const TrustRegionStrategy::Options& options);
+ public:
+ explicit LevenbergMarquardtStrategy(
+ const TrustRegionStrategy::Options& options);
virtual ~LevenbergMarquardtStrategy();
// TrustRegionStrategy interface
diff --git a/extern/libmv/third_party/ceres/internal/ceres/line_search.cc b/extern/libmv/third_party/ceres/internal/ceres/line_search.cc
new file mode 100644
index 00000000000..e7508caec56
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/line_search.cc
@@ -0,0 +1,211 @@
+// 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.h"
+
+#include <glog/logging.h>
+#include "ceres/fpclassify.h"
+#include "ceres/evaluator.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/polynomial.h"
+
+
+namespace ceres {
+namespace internal {
+namespace {
+
+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
+
+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(const 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);
+}
+
+void ArmijoLineSearch::Search(const LineSearch::Options& options,
+ const double initial_step_size,
+ const double initial_cost,
+ const double initial_gradient,
+ Summary* summary) {
+ *CHECK_NOTNULL(summary) = LineSearch::Summary();
+ Function* function = options.function;
+
+ double previous_step_size = 0.0;
+ double previous_cost = 0.0;
+ double previous_gradient = 0.0;
+ bool previous_step_size_is_valid = false;
+
+ double step_size = initial_step_size;
+ double cost = 0.0;
+ double gradient = 0.0;
+ bool step_size_is_valid = false;
+
+ ++summary->num_evaluations;
+ step_size_is_valid =
+ function->Evaluate(step_size,
+ &cost,
+ options.interpolation_degree < 2 ? NULL : &gradient);
+ while (!step_size_is_valid || cost > (initial_cost
+ + options.sufficient_decrease
+ * initial_gradient
+ * step_size)) {
+ // If step_size_is_valid is not true we treat it as if the cost at
+ // that point is not large enough to satisfy the sufficient
+ // decrease condition.
+
+ const double current_step_size = step_size;
+ // Backtracking search. Each iteration of this loop finds a new point
+
+ if ((options.interpolation_degree == 0) || !step_size_is_valid) {
+ // Backtrack by halving the step_size;
+ step_size *= 0.5;
+ } else {
+ // Backtrack by interpolating the function and gradient values
+ // and minimizing the corresponding polynomial.
+
+ vector<FunctionSample> samples;
+ samples.push_back(ValueAndGradientSample(0.0,
+ initial_cost,
+ initial_gradient));
+
+ if (options.interpolation_degree == 1) {
+ // Two point interpolation using function values and the
+ // initial gradient.
+ samples.push_back(ValueSample(step_size, cost));
+
+ if (options.use_higher_degree_interpolation_when_possible &&
+ summary->num_evaluations > 1 &&
+ previous_step_size_is_valid) {
+ // Three point interpolation, using function values and the
+ // initial gradient.
+ samples.push_back(ValueSample(previous_step_size, previous_cost));
+ }
+ } else {
+ // Two point interpolation using the function values and the gradients.
+ samples.push_back(ValueAndGradientSample(step_size,
+ cost,
+ gradient));
+
+ if (options.use_higher_degree_interpolation_when_possible &&
+ summary->num_evaluations > 1 &&
+ previous_step_size_is_valid) {
+ // Three point interpolation using the function values and
+ // the gradients.
+ samples.push_back(ValueAndGradientSample(previous_step_size,
+ previous_cost,
+ previous_gradient));
+ }
+ }
+
+ double min_value;
+ MinimizeInterpolatingPolynomial(samples, 0.0, current_step_size,
+ &step_size, &min_value);
+ step_size =
+ min(max(step_size,
+ options.min_relative_step_size_change * current_step_size),
+ options.max_relative_step_size_change * current_step_size);
+ }
+
+ previous_step_size = current_step_size;
+ previous_cost = cost;
+ previous_gradient = gradient;
+
+ if (fabs(initial_gradient) * step_size < options.step_size_threshold) {
+ LOG(WARNING) << "Line search failed: step_size too small: " << step_size;
+ return;
+ }
+
+ ++summary->num_evaluations;
+ step_size_is_valid =
+ function->Evaluate(step_size,
+ &cost,
+ options.interpolation_degree < 2 ? NULL : &gradient);
+ }
+
+ summary->optimal_step_size = step_size;
+ summary->success = 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
new file mode 100644
index 00000000000..fccf63b598a
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/line_search.h
@@ -0,0 +1,212 @@
+// 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 <glog/logging.h>
+#include <vector>
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+
+namespace ceres {
+namespace internal {
+
+class Evaluator;
+
+// 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_degree(1),
+ use_higher_degree_interpolation_when_possible(false),
+ sufficient_decrease(1e-4),
+ min_relative_step_size_change(1e-3),
+ max_relative_step_size_change(0.6),
+ step_size_threshold(1e-9),
+ function(NULL) {}
+
+ // TODO(sameeragarwal): Replace this with enums which are common
+ // across various line searches.
+ //
+ // Degree of the polynomial used to approximate the objective
+ // function. Valid values are {0, 1, 2}.
+ //
+ // For Armijo line search
+ //
+ // 0: Bisection based backtracking search.
+ // 1: Quadratic interpolation.
+ // 2: Cubic interpolation.
+ int interpolation_degree;
+
+ // Usually its possible to increase the degree of the
+ // interpolation polynomial by storing and using an extra point.
+ bool use_higher_degree_interpolation_when_possible;
+
+ // Armijo 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 line search,
+ //
+ // new_step_size >= min_relative_step_size_change * step_size
+ double min_relative_step_size_change;
+
+ // In each iteration of the Armijo line search,
+ //
+ // new_step_size <= max_relative_step_size_change * step_size
+ double max_relative_step_size_change;
+
+ // If during the line search, the step_size falls below this
+ // value, it is truncated to zero.
+ double step_size_threshold;
+
+ // 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_evaluations(0) {}
+
+ bool success;
+ double optimal_step_size;
+ int num_evaluations;
+ };
+
+ virtual ~LineSearch() {}
+
+ // Perform the line search.
+ //
+ // initial_step_size 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(const LineSearch::Options& options,
+ double initial_step_size,
+ double initial_cost,
+ double initial_gradient,
+ Summary* summary) = 0;
+};
+
+class LineSearchFunction : public LineSearch::Function {
+ public:
+ explicit LineSearchFunction(Evaluator* evaluator);
+ virtual ~LineSearchFunction() {}
+ void Init(const Vector& position, const Vector& direction);
+ virtual bool Evaluate(const double x, double* f, double* g);
+
+ 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:
+ virtual ~ArmijoLineSearch() {}
+ virtual void Search(const LineSearch::Options& options,
+ double initial_step_size,
+ double initial_cost,
+ double initial_gradient,
+ 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
new file mode 100644
index 00000000000..2f27a78301a
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.cc
@@ -0,0 +1,145 @@
+// 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_RIBIRERE:
+ 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)
+ : low_rank_inverse_hessian_(num_parameters, max_lbfgs_rank) {}
+
+ virtual ~LBFGS() {}
+
+ bool NextDirection(const LineSearchMinimizer::State& previous,
+ const LineSearchMinimizer::State& current,
+ Vector* search_direction) {
+ 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;
+ return true;
+ }
+
+ private:
+ LowRankInverseHessian low_rank_inverse_hessian_;
+};
+
+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);
+ }
+
+ 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/polynomial_solver.h b/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.h
index 1cf07ddb549..71063ab8414 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/line_search_direction.h
@@ -26,40 +26,45 @@
// 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)
+// Author: sameeragarwal@google.com (Sameer Agarwal)
-#ifndef CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
-#define CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
+#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 {
-// Use the companion matrix eigenvalues to determine the roots of the polynomial
-//
-// sum_{i=0}^N polynomial(i) x^{N-i}.
-//
-// 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);
+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) {
+ }
+
+ int num_parameters;
+ LineSearchDirectionType type;
+ NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
+ double function_tolerance;
+ int max_lbfgs_rank;
+ };
+
+ static LineSearchDirection* Create(const Options& options);
-// 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;
-}
+ virtual ~LineSearchDirection() {}
+ virtual bool NextDirection(const LineSearchMinimizer::State& previous,
+ const LineSearchMinimizer::State& current,
+ Vector* search_direction) = 0;
+};
} // namespace internal
} // namespace ceres
-#endif // CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
+#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
new file mode 100644
index 00000000000..ca7d639c5ef
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.cc
@@ -0,0 +1,283 @@
+// 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 {
+// Small constant for various floating point issues.
+// TODO(sameeragarwal): Change to a better name if this has only one
+// use.
+const double kEpsilon = 1e-12;
+
+bool Evaluate(Evaluator* evaluator,
+ const Vector& x,
+ LineSearchMinimizer::State* state) {
+ const bool status = evaluator->Evaluate(x.data(),
+ &(state->cost),
+ NULL,
+ state->gradient.data(),
+ NULL);
+ if (status) {
+ state->gradient_squared_norm = state->gradient.squaredNorm();
+ state->gradient_max_norm = state->gradient.lpNorm<Eigen::Infinity>();
+ }
+
+ return status;
+}
+
+} // namespace
+
+void LineSearchMinimizer::Minimize(const Minimizer::Options& options,
+ double* parameters,
+ Solver::Summary* summary) {
+ double start_time = WallTimeInSeconds();
+ double iteration_start_time = start_time;
+
+ Evaluator* evaluator = CHECK_NOTNULL(options.evaluator);
+ 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.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)) {
+ LOG(WARNING) << "Terminating: Cost and gradient evaluation failed.";
+ summary->termination_type = NUMERICAL_FAILURE;
+ 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;
+
+ // The initial gradient max_norm is bounded from below so that we do
+ // not divide by zero.
+ const double initial_gradient_max_norm =
+ max(iteration_summary.gradient_max_norm, kEpsilon);
+ const double absolute_gradient_tolerance =
+ options.gradient_tolerance * initial_gradient_max_norm;
+
+ if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) {
+ summary->termination_type = GRADIENT_TOLERANCE;
+ VLOG(1) << "Terminating: Gradient tolerance reached."
+ << "Relative gradient max norm: "
+ << iteration_summary.gradient_max_norm / initial_gradient_max_norm
+ << " <= " << options.gradient_tolerance;
+ 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;
+ 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.function = &line_search_function;
+
+ // TODO(sameeragarwal): Make this parameterizable over different
+ // line searches.
+ ArmijoLineSearch line_search;
+ LineSearch::Summary line_search_summary;
+
+ while (true) {
+ if (!RunCallbacks(options.callbacks, iteration_summary, summary)) {
+ return;
+ }
+
+ iteration_start_time = WallTimeInSeconds();
+ if (iteration_summary.iteration >= options.max_num_iterations) {
+ summary->termination_type = NO_CONVERGENCE;
+ VLOG(1) << "Terminating: Maximum number of iterations reached.";
+ 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->termination_type = NO_CONVERGENCE;
+ VLOG(1) << "Terminating: Maximum solver time reached.";
+ break;
+ }
+
+ iteration_summary = IterationSummary();
+ iteration_summary.iteration = summary->iterations.back().iteration + 1;
+
+ 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) {
+ LOG(WARNING) << "Line search direction computation failed. "
+ "Resorting to steepest descent.";
+ 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.
+ const double initial_step_size = (iteration_summary.iteration == 1)
+ ? 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);
+
+ line_search.Search(line_search_options,
+ initial_step_size,
+ current_state.cost,
+ current_state.directional_derivative,
+ &line_search_summary);
+
+ current_state.step_size = line_search_summary.optimal_step_size;
+ delta = current_state.step_size * current_state.search_direction;
+
+ previous_state = current_state;
+
+ // TODO(sameeragarwal): Collect stats.
+ if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data()) ||
+ !Evaluate(evaluator, x_plus_delta, &current_state)) {
+ LOG(WARNING) << "Evaluation failed.";
+ } else {
+ x = x_plus_delta;
+ }
+
+ iteration_summary.gradient_max_norm = current_state.gradient_max_norm;
+ if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) {
+ summary->termination_type = GRADIENT_TOLERANCE;
+ VLOG(1) << "Terminating: Gradient tolerance reached."
+ << "Relative gradient max norm: "
+ << iteration_summary.gradient_max_norm / initial_gradient_max_norm
+ << " <= " << options.gradient_tolerance;
+ break;
+ }
+
+ iteration_summary.cost_change = previous_state.cost - current_state.cost;
+ const double absolute_function_tolerance =
+ options.function_tolerance * previous_state.cost;
+ if (fabs(iteration_summary.cost_change) < absolute_function_tolerance) {
+ VLOG(1) << "Terminating. Function tolerance reached. "
+ << "|cost_change|/cost: "
+ << fabs(iteration_summary.cost_change) / previous_state.cost
+ << " <= " << options.function_tolerance;
+ summary->termination_type = FUNCTION_TOLERANCE;
+ return;
+ }
+
+ 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_evaluations;
+ 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/line_search_minimizer.h b/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.h
new file mode 100644
index 00000000000..f82f13984a8
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/line_search_minimizer.h
@@ -0,0 +1,77 @@
+// 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/linear_least_squares_problems.cc b/extern/libmv/third_party/ceres/internal/ceres/linear_least_squares_problems.cc
index a91e254a663..6c886a1be38 100644
--- 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
@@ -573,13 +573,14 @@ LinearLeastSquaresProblem* LinearLeastSquaresProblem3() {
return problem;
}
-static bool DumpLinearLeastSquaresProblemToConsole(const string& directory,
- int iteration,
- const SparseMatrix* A,
- const double* D,
- const double* b,
- const double* x,
- int num_eliminate_blocks) {
+namespace {
+bool DumpLinearLeastSquaresProblemToConsole(const string& directory,
+ int iteration,
+ const SparseMatrix* A,
+ const double* D,
+ const double* b,
+ const double* x,
+ int num_eliminate_blocks) {
CHECK_NOTNULL(A);
Matrix AA;
A->ToDenseMatrix(&AA);
@@ -601,13 +602,13 @@ static bool DumpLinearLeastSquaresProblemToConsole(const string& directory,
};
#ifndef CERES_NO_PROTOCOL_BUFFERS
-static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
- int iteration,
- const SparseMatrix* A,
- const double* D,
- const double* b,
- const double* x,
- int num_eliminate_blocks) {
+bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
+ int iteration,
+ const SparseMatrix* A,
+ const double* D,
+ const double* b,
+ const double* x,
+ int num_eliminate_blocks) {
CHECK_NOTNULL(A);
LinearLeastSquaresProblemProto lsqp;
A->ToProto(lsqp.mutable_a());
@@ -641,13 +642,13 @@ static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& director
return true;
}
#else
-static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
- int iteration,
- const SparseMatrix* A,
- const double* D,
- const double* b,
- const double* x,
- int num_eliminate_blocks) {
+bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
+ int iteration,
+ const SparseMatrix* A,
+ const double* D,
+ const double* b,
+ const double* x,
+ int num_eliminate_blocks) {
LOG(ERROR) << "Dumping least squares problems is only "
<< "supported when Ceres is compiled with "
<< "protocol buffer support.";
@@ -655,9 +656,9 @@ static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& director
}
#endif
-static void WriteArrayToFileOrDie(const string& filename,
- const double* x,
- const int size) {
+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");
@@ -668,13 +669,13 @@ static void WriteArrayToFileOrDie(const string& filename,
fclose(fptr);
}
-static bool DumpLinearLeastSquaresProblemToTextFile(const string& directory,
- int iteration,
- const SparseMatrix* A,
- const double* D,
- const double* b,
- const double* x,
- int num_eliminate_blocks) {
+bool DumpLinearLeastSquaresProblemToTextFile(const string& directory,
+ int iteration,
+ const SparseMatrix* A,
+ const double* D,
+ const double* b,
+ const double* x,
+ int num_eliminate_blocks) {
CHECK_NOTNULL(A);
string format_string = JoinPath(directory,
"lm_iteration_%03d");
@@ -732,9 +733,10 @@ static bool DumpLinearLeastSquaresProblemToTextFile(const string& directory,
WriteStringToFileOrDie(matlab_script, matlab_filename);
return true;
}
+} // namespace
bool DumpLinearLeastSquaresProblem(const string& directory,
- int iteration,
+ int iteration,
DumpFormatType dump_format_type,
const SparseMatrix* A,
const double* D,
@@ -742,18 +744,18 @@ bool DumpLinearLeastSquaresProblem(const string& directory,
const double* x,
int num_eliminate_blocks) {
switch (dump_format_type) {
- case (CONSOLE):
+ case CONSOLE:
return DumpLinearLeastSquaresProblemToConsole(directory,
iteration,
A, D, b, x,
num_eliminate_blocks);
- case (PROTOBUF):
+ case PROTOBUF:
return DumpLinearLeastSquaresProblemToProtocolBuffer(
directory,
iteration,
A, D, b, x,
num_eliminate_blocks);
- case (TEXTFILE):
+ case TEXTFILE:
return DumpLinearLeastSquaresProblemToTextFile(directory,
iteration,
A, D, b, x,
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
index 553cc0d3db3..c76ae91c7d8 100644
--- 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
@@ -74,7 +74,7 @@ LinearLeastSquaresProblem* LinearLeastSquaresProblem3();
// Write the linear least squares problem to disk. The exact format
// depends on dump_format_type.
bool DumpLinearLeastSquaresProblem(const string& directory,
- int iteration,
+ int iteration,
DumpFormatType dump_format_type,
const SparseMatrix* A,
const double* D,
diff --git a/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h b/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h
index 31f88740b9f..a98051468e7 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/linear_solver.h
@@ -35,14 +35,16 @@
#define CERES_INTERNAL_LINEAR_SOLVER_H_
#include <cstddef>
-
-#include <glog/logging.h>
+#include <map>
+#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 {
@@ -76,7 +78,6 @@ class LinearSolver {
min_num_iterations(1),
max_num_iterations(1),
num_threads(1),
- num_eliminate_blocks(0),
residual_reset_period(10),
row_block_size(Dynamic),
e_block_size(Dynamic),
@@ -100,15 +101,23 @@ class LinearSolver {
// If possible, how many threads can the solver use.
int num_threads;
- // Eliminate 0 to num_eliminate_blocks - 1 from the Normal
- // equations to form a schur complement. Only used by the Schur
- // complement based solver. The most common use for this parameter
- // is in the case of structure from motion problems where we have
- // camera blocks and point blocks. Then setting the
- // num_eliminate_blocks to the number of points allows the solver
- // to use the Schur complement trick. For more details see the
- // description of this parameter in solver.h.
- int num_eliminate_blocks;
+ // 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] 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
@@ -247,6 +256,18 @@ class LinearSolver {
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);
};
@@ -267,18 +288,29 @@ class TypedLinearSolver : public LinearSolver {
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
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
new file mode 100644
index 00000000000..3fe113f1afb
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc
@@ -0,0 +1,109 @@
+// 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/internal/eigen.h"
+#include "ceres/low_rank_inverse_hessian.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+LowRankInverseHessian::LowRankInverseHessian(int num_parameters,
+ int max_num_corrections)
+ : num_parameters_(num_parameters),
+ max_num_corrections_(max_num_corrections),
+ num_corrections_(0),
+ diagonal_(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 <= 1e-10) {
+ VLOG(2) << "Skipping LBFGS Update. " << delta_x_dot_delta_gradient;
+ return false;
+ }
+
+ if (num_corrections_ == max_num_corrections_) {
+ // TODO(sameeragarwal): This can be done more efficiently using
+ // a circular buffer/indexing scheme, but for simplicity we will
+ // do the expensive copy for now.
+ delta_x_history_.block(0, 0, num_parameters_, max_num_corrections_ - 2) =
+ delta_x_history_
+ .block(0, 1, num_parameters_, max_num_corrections_ - 1);
+
+ delta_gradient_history_
+ .block(0, 0, num_parameters_, max_num_corrections_ - 2) =
+ delta_gradient_history_
+ .block(0, 1, num_parameters_, max_num_corrections_ - 1);
+
+ delta_x_dot_delta_gradient_.head(num_corrections_ - 2) =
+ delta_x_dot_delta_gradient_.tail(num_corrections_ - 1);
+ } else {
+ ++num_corrections_;
+ }
+
+ delta_x_history_.col(num_corrections_ - 1) = delta_x;
+ delta_gradient_history_.col(num_corrections_ - 1) = delta_gradient;
+ delta_x_dot_delta_gradient_(num_corrections_ - 1) =
+ delta_x_dot_delta_gradient;
+ diagonal_ = 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;
+
+ Vector alpha(num_corrections_);
+
+ for (int i = num_corrections_ - 1; i >= 0; --i) {
+ alpha(i) = delta_x_history_.col(i).dot(search_direction) /
+ delta_x_dot_delta_gradient_(i);
+ search_direction -= alpha(i) * delta_gradient_history_.col(i);
+ }
+
+ search_direction *= diagonal_;
+
+ for (int i = 0; i < num_corrections_; ++i) {
+ const double beta = delta_gradient_history_.col(i).dot(search_direction) /
+ delta_x_dot_delta_gradient_(i);
+ search_direction += delta_x_history_.col(i) * (alpha(i) - 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
new file mode 100644
index 00000000000..6f3fc0c9d00
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h
@@ -0,0 +1,99 @@
+// 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 "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.
+ // The approximation uses:
+ // 2 * max_num_corrections * num_parameters + max_num_corrections
+ // doubles.
+ LowRankInverseHessian(int num_parameters, int max_num_corrections);
+ 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_;
+ int num_corrections_;
+ double diagonal_;
+ Matrix delta_x_history_;
+ Matrix delta_gradient_history_;
+ Vector delta_x_dot_delta_gradient_;
+};
+
+} // 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
index ddf1252f674..929c6b36982 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/map_util.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/map_util.h
@@ -35,6 +35,7 @@
#include <utility>
#include "ceres/internal/port.h"
+#include "glog/logging.h"
namespace ceres {
diff --git a/extern/libmv/third_party/ceres/internal/ceres/minimizer.cc b/extern/libmv/third_party/ceres/internal/ceres/minimizer.cc
new file mode 100644
index 00000000000..2e2c15ac612
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/minimizer.cc
@@ -0,0 +1,67 @@
+// 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/minimizer.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace internal {
+
+Minimizer::~Minimizer() {}
+
+bool Minimizer::RunCallbacks(const vector<IterationCallback*> callbacks,
+ const IterationSummary& iteration_summary,
+ Solver::Summary* summary) {
+ CallbackReturnType status = SOLVER_CONTINUE;
+ int i = 0;
+ while (status == SOLVER_CONTINUE && i < callbacks.size()) {
+ status = (*callbacks[i])(iteration_summary);
+ ++i;
+ }
+ switch (status) {
+ case SOLVER_CONTINUE:
+ return true;
+ case SOLVER_TERMINATE_SUCCESSFULLY:
+ summary->termination_type = USER_SUCCESS;
+ VLOG(1) << "Terminating: User callback returned USER_SUCCESS.";
+ return false;
+ case SOLVER_ABORT:
+ summary->termination_type = USER_ABORT;
+ VLOG(1) << "Terminating: User callback returned USER_ABORT.";
+ 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
index cfc98a3ebd0..708974d63c2 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/minimizer.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/minimizer.h
@@ -32,8 +32,9 @@
#define CERES_INTERNAL_MINIMIZER_H_
#include <vector>
-#include "ceres/solver.h"
+#include "ceres/internal/port.h"
#include "ceres/iteration_callback.h"
+#include "ceres/solver.h"
namespace ceres {
namespace internal {
@@ -59,6 +60,7 @@ class Minimizer {
}
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;
@@ -74,18 +76,24 @@ class Minimizer {
lsqp_dump_directory = options.lsqp_dump_directory;
lsqp_iterations_to_dump = options.lsqp_iterations_to_dump;
lsqp_dump_format_type = options.lsqp_dump_format_type;
- num_eliminate_blocks = options.num_eliminate_blocks;
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;
evaluator = NULL;
trust_region_strategy = NULL;
jacobian = NULL;
callbacks = options.callbacks;
+ inner_iteration_minimizer = NULL;
}
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
@@ -104,9 +112,12 @@ class Minimizer {
vector<int> lsqp_iterations_to_dump;
DumpFormatType lsqp_dump_format_type;
string lsqp_dump_directory;
- int num_eliminate_blocks;
int max_num_consecutive_invalid_steps;
int min_trust_region_radius;
+ LineSearchDirectionType line_search_direction_type;
+ LineSearchType line_search_type;
+ NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
+ int max_lbfgs_rank;
// List of callbacks that are executed by the Minimizer at the end
// of each iteration.
@@ -128,10 +139,15 @@ class Minimizer {
// and will remain constant for the life time of the
// optimization. The Options struct does not own this pointer.
SparseMatrix* jacobian;
+
+ Minimizer* inner_iteration_minimizer;
};
- virtual ~Minimizer() {}
+ static bool RunCallbacks(const vector<IterationCallback*> callbacks,
+ 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.
diff --git a/extern/libmv/third_party/ceres/internal/ceres/mutex.h b/extern/libmv/third_party/ceres/internal/ceres/mutex.h
index 5090a71b78d..410748ff0ab 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/mutex.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/mutex.h
@@ -107,10 +107,12 @@
# 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 CERES_NOGDI
+# define NOGDI
// To avoid macro definition of min/max.
-# define CERES_NOMINMAX
+# define NOMINMAX
# include <windows.h>
typedef CRITICAL_SECTION MutexType;
#elif defined(CERES_HAVE_PTHREAD) && defined(CERES_HAVE_RWLOCK)
diff --git a/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h b/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h
index f20805ca873..b1e8d938b8a 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/parameter_block.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2010, 2011, 2012 Google Inc. All rights reserved.
+// 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
@@ -34,6 +34,7 @@
#include <cstdlib>
#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"
@@ -46,6 +47,7 @@ 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
@@ -58,13 +60,29 @@ class ProblemImpl;
// responsible for the proper disposal of the local parameterization.
class ParameterBlock {
public:
- ParameterBlock(double* user_state, int size) {
- Init(user_state, size, NULL);
+ // 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, local_parameterization);
+ Init(user_state, size, index, local_parameterization);
}
// The size of the parameter block.
@@ -187,12 +205,43 @@ class ParameterBlock {
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();
+ }
+
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_;
@@ -201,7 +250,6 @@ class ParameterBlock {
SetParameterization(local_parameterization);
}
- index_ = -1;
state_offset_ = -1;
delta_offset_ = -1;
}
@@ -261,6 +309,9 @@ class ParameterBlock {
// 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_;
+
// Necessary so ProblemImpl can clean up the parameterizations.
friend class ProblemImpl;
};
diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.cc b/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.cc
index 1cdff4e6dec..e8f626f8e80 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.cc
@@ -28,7 +28,7 @@
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
-#include "ceres/schur_ordering.h"
+#include "ceres/parameter_block_ordering.h"
#include "ceres/graph.h"
#include "ceres/graph_algorithms.h"
@@ -46,8 +46,7 @@ int ComputeSchurOrdering(const Program& program,
vector<ParameterBlock*>* ordering) {
CHECK_NOTNULL(ordering)->clear();
- scoped_ptr<Graph< ParameterBlock*> > graph(
- CHECK_NOTNULL(CreateHessianGraph(program)));
+ scoped_ptr<Graph< ParameterBlock*> > graph(CreateHessianGraph(program));
int independent_set_size = IndependentSetOrdering(*graph, ordering);
const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
@@ -62,9 +61,31 @@ int ComputeSchurOrdering(const Program& program,
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 = new Graph<ParameterBlock*>;
+ 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];
diff --git a/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.h b/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.h
index 1f9a4ff354f..a5277a44c70 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_ordering.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/parameter_block_ordering.h
@@ -27,14 +27,12 @@
// POSSIBILITY OF SUCH DAMAGE.
//
// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Compute a parameter block ordering for use with the Schur
-// complement based algorithms.
-#ifndef CERES_INTERNAL_SCHUR_ORDERING_H_
-#define CERES_INTERNAL_SCHUR_ORDERING_H_
+#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"
@@ -60,6 +58,12 @@ class ParameterBlock;
int ComputeSchurOrdering(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
@@ -71,4 +75,4 @@ Graph<ParameterBlock*>* CreateHessianGraph(const Program& program);
} // namespace internal
} // namespace ceres
-#endif // CERES_INTERNAL_SCHUR_ORDERING_H_
+#endif // CERES_INTERNAL_PARAMETER_BLOCK_ORDERING_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.cc b/extern/libmv/third_party/ceres/internal/ceres/polynomial.cc
index 20c01566a89..3238b89670e 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/polynomial_solver.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/polynomial.cc
@@ -27,11 +27,14 @@
// POSSIBILITY OF SUCH DAMAGE.
//
// Author: moll.markus@arcor.de (Markus Moll)
+// sameeragarwal@google.com (Sameer Agarwal)
-#include "ceres/polynomial_solver.h"
+#include "ceres/polynomial.h"
#include <cmath>
#include <cstddef>
+#include <vector>
+
#include "Eigen/Dense"
#include "ceres/internal/port.h"
#include "glog/logging.h"
@@ -159,8 +162,7 @@ bool FindPolynomialRoots(const Vector& polynomial_in,
BalanceCompanionMatrix(&companion_matrix);
// Find its (complex) eigenvalues.
- Eigen::EigenSolver<Matrix> solver(companion_matrix,
- Eigen::EigenvaluesOnly);
+ Eigen::EigenSolver<Matrix> solver(companion_matrix, false);
if (solver.info() != Eigen::Success) {
LOG(ERROR) << "Failed to extract eigenvalues from companion matrix.";
return false;
@@ -180,5 +182,138 @@ bool FindPolynomialRoots(const Vector& polynomial_in,
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;
+ }
+ }
+}
+
+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
new file mode 100644
index 00000000000..42ffdcb13c5
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/polynomial.h
@@ -0,0 +1,134 @@
+// 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) {
+ }
+
+ 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
new file mode 100644
index 00000000000..05e539f9fb1
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/preconditioner.cc
@@ -0,0 +1,63 @@
+// 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() {
+}
+
+SparseMatrixPreconditionerWrapper::SparseMatrixPreconditionerWrapper(
+ const SparseMatrix* matrix)
+ : matrix_(CHECK_NOTNULL(matrix)) {
+}
+
+SparseMatrixPreconditionerWrapper::~SparseMatrixPreconditionerWrapper() {
+}
+
+bool SparseMatrixPreconditionerWrapper::Update(const BlockSparseMatrixBase& 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
new file mode 100644
index 00000000000..5bb077e0e33
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/preconditioner.h
@@ -0,0 +1,148 @@
+// 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/linear_operator.h"
+#include "ceres/sparse_matrix.h"
+
+namespace ceres {
+namespace internal {
+
+class BlockSparseMatrixBase;
+class SparseMatrix;
+
+class Preconditioner : public LinearOperator {
+ public:
+ struct Options {
+ Options()
+ : type(JACOBI),
+ sparse_linear_algebra_library(SUITE_SPARSE),
+ use_block_amd(true),
+ num_threads(1),
+ row_block_size(Dynamic),
+ e_block_size(Dynamic),
+ f_block_size(Dynamic) {
+ }
+
+ PreconditionerType type;
+
+ SparseLinearAlgebraLibraryType sparse_linear_algebra_library;
+
+ // See solver.h for explanation of this option.
+ bool use_block_amd;
+
+ // 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] 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;
+ };
+
+ 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 BlockSparseMatrixBase& 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();
+ }
+};
+
+// Wrap a SparseMatrix object as a preconditioner.
+class SparseMatrixPreconditionerWrapper : public Preconditioner {
+ public:
+ // Wrapper does NOT take ownership of the matrix pointer.
+ explicit SparseMatrixPreconditionerWrapper(const SparseMatrix* matrix);
+ virtual ~SparseMatrixPreconditionerWrapper();
+
+ // Preconditioner interface
+ virtual bool Update(const BlockSparseMatrixBase& A, const double* D);
+ virtual void RightMultiply(const double* x, double* y) const;
+ virtual int num_rows() const;
+
+ private:
+ const SparseMatrix* matrix_;
+};
+
+} // namespace internal
+} // namespace ceres
+
+#endif // CERES_INTERNAL_PRECONDITIONER_H_
diff --git a/extern/libmv/third_party/ceres/internal/ceres/problem.cc b/extern/libmv/third_party/ceres/internal/ceres/problem.cc
index b8c25d9db84..43e78835b15 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/problem.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/problem.cc
@@ -32,12 +32,11 @@
#include "ceres/problem.h"
#include <vector>
+#include "ceres/crs_matrix.h"
#include "ceres/problem_impl.h"
namespace ceres {
-class ResidualBlock;
-
Problem::Problem() : problem_impl_(new internal::ProblemImpl) {}
Problem::Problem(const Problem::Options& options)
: problem_impl_(new internal::ProblemImpl(options)) {}
@@ -106,6 +105,47 @@ ResidualBlockId Problem::AddResidualBlock(
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);
}
@@ -116,6 +156,14 @@ void Problem::AddParameterBlock(double* values,
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);
}
@@ -130,6 +178,18 @@ void Problem::SetParameterization(
problem_impl_->SetParameterization(values, local_parameterization);
}
+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();
}
diff --git a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc
index c186f527be8..bc378aaafff 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.cc
@@ -37,7 +37,11 @@
#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"
@@ -73,54 +77,103 @@ static void CheckForNoAliasing(double* existing_block,
<< "size " << new_block_size << ".";
}
-static ParameterBlock* InternalAddParameterBlock(
- double* values,
- int size,
- ParameterMap* parameter_map,
- vector<ParameterBlock*>* parameter_blocks) {
- CHECK(values) << "Null pointer passed to AddParameterBlock for a parameter "
- << "with size " << size;
+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_map->find(values);
- if (it != parameter_map->end()) {
- 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;
+ 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;
}
- // Before adding the parameter block, also check that it doesn't alias any
- // other parameter blocks.
- if (!parameter_map->empty()) {
- ParameterMap::iterator lb = parameter_map->lower_bound(values);
-
- // If lb is not the first block, check the previous block for aliasing.
- if (lb != parameter_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_map->end()) {
- CheckForNoAliasing(lb->first,
- lb->second->Size(),
- values,
- size);
+ 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);
+ }
}
}
- ParameterBlock* new_parameter_block = new ParameterBlock(values, size);
- (*parameter_map)[values] = new_parameter_block;
- parameter_blocks->push_back(new_parameter_block);
+
+ // 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_parameter_block_removal) {
+ new_parameter_block->EnableResidualBlockDependencies();
+ }
+ parameter_block_map_[values] = new_parameter_block;
+ program_->parameter_blocks_.push_back(new_parameter_block);
return new_parameter_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),
@@ -128,48 +181,28 @@ ProblemImpl::ProblemImpl(const Problem::Options& options)
ProblemImpl::~ProblemImpl() {
// Collect the unique cost/loss functions and delete the residuals.
- set<CostFunction*> cost_functions;
- set<LossFunction*> loss_functions;
+ 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) {
- ResidualBlock* residual_block = program_->residual_blocks_[i];
-
- // 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) {
- cost_functions.insert(
- const_cast<CostFunction*>(residual_block->cost_function()));
- }
- if (options_.loss_function_ownership == TAKE_OWNERSHIP) {
- loss_functions.insert(
- const_cast<LossFunction*>(residual_block->loss_function()));
- }
-
- delete residual_block;
+ DeleteBlock(program_->residual_blocks_[i]);
}
// Collect the unique parameterizations and delete the parameters.
- set<LocalParameterization*> local_parameterizations;
for (int i = 0; i < program_->parameter_blocks_.size(); ++i) {
- ParameterBlock* parameter_block = program_->parameter_blocks_[i];
-
- if (options_.local_parameterization_ownership == TAKE_OWNERSHIP) {
- local_parameterizations.insert(parameter_block->local_parameterization_);
- }
-
- delete parameter_block;
+ DeleteBlock(program_->parameter_blocks_[i]);
}
// Delete the owned cost/loss functions and parameterizations.
- STLDeleteContainerPointers(local_parameterizations.begin(),
- local_parameterizations.end());
- STLDeleteContainerPointers(cost_functions.begin(),
- cost_functions.end());
- STLDeleteContainerPointers(loss_functions.begin(),
- loss_functions.end());
+ 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());
}
-const ResidualBlock* ProblemImpl::AddResidualBlock(
+ResidualBlock* ProblemImpl::AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
const vector<double*>& parameter_blocks) {
@@ -180,25 +213,28 @@ const ResidualBlock* ProblemImpl::AddResidualBlock(
// Check the sizes match.
const vector<int16>& parameter_block_sizes =
cost_function->parameter_block_sizes();
- 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 += internal::StringPrintf(" %p ", parameter_blocks[i]);
- }
- LOG(FATAL) << "Duplicate parameter blocks in a residual parameter "
- << "are not allowed. Parameter block pointers: ["
- << blocks << "]";
+ 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.
@@ -206,33 +242,42 @@ const ResidualBlock* ProblemImpl::AddResidualBlock(
for (int i = 0; i < parameter_blocks.size(); ++i) {
parameter_block_ptrs[i] =
InternalAddParameterBlock(parameter_blocks[i],
- parameter_block_sizes[i],
- &parameter_block_map_,
- &program_->parameter_blocks_);
+ parameter_block_sizes[i]);
}
- // 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();
+ 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);
+ parameter_block_ptrs,
+ program_->residual_blocks_.size());
+
+ // Add dependencies on the residual to the parameter blocks.
+ if (options_.enable_fast_parameter_block_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);
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.
-const ResidualBlock* ProblemImpl::AddResidualBlock(
+ResidualBlock* ProblemImpl::AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
double* x0) {
@@ -241,7 +286,7 @@ const ResidualBlock* ProblemImpl::AddResidualBlock(
return AddResidualBlock(cost_function, loss_function, residual_parameters);
}
-const ResidualBlock* ProblemImpl::AddResidualBlock(
+ResidualBlock* ProblemImpl::AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
double* x0, double* x1) {
@@ -251,7 +296,7 @@ const ResidualBlock* ProblemImpl::AddResidualBlock(
return AddResidualBlock(cost_function, loss_function, residual_parameters);
}
-const ResidualBlock* ProblemImpl::AddResidualBlock(
+ResidualBlock* ProblemImpl::AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
double* x0, double* x1, double* x2) {
@@ -262,7 +307,7 @@ const ResidualBlock* ProblemImpl::AddResidualBlock(
return AddResidualBlock(cost_function, loss_function, residual_parameters);
}
-const ResidualBlock* ProblemImpl::AddResidualBlock(
+ResidualBlock* ProblemImpl::AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
double* x0, double* x1, double* x2, double* x3) {
@@ -274,7 +319,7 @@ const ResidualBlock* ProblemImpl::AddResidualBlock(
return AddResidualBlock(cost_function, loss_function, residual_parameters);
}
-const ResidualBlock* ProblemImpl::AddResidualBlock(
+ResidualBlock* ProblemImpl::AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
double* x0, double* x1, double* x2, double* x3, double* x4) {
@@ -287,7 +332,7 @@ const ResidualBlock* ProblemImpl::AddResidualBlock(
return AddResidualBlock(cost_function, loss_function, residual_parameters);
}
-const ResidualBlock* ProblemImpl::AddResidualBlock(
+ResidualBlock* ProblemImpl::AddResidualBlock(
CostFunction* cost_function,
LossFunction* loss_function,
double* x0, double* x1, double* x2, double* x3, double* x4, double* x5) {
@@ -301,12 +346,78 @@ const ResidualBlock* ProblemImpl::AddResidualBlock(
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,
- &parameter_block_map_,
- &program_->parameter_blocks_);
+ InternalAddParameterBlock(values, size);
}
void ProblemImpl::AddParameterBlock(
@@ -314,15 +425,83 @@ void ProblemImpl::AddParameterBlock(
int size,
LocalParameterization* local_parameterization) {
ParameterBlock* parameter_block =
- InternalAddParameterBlock(values,
- size,
- &parameter_block_map_,
- &program_->parameter_blocks_);
+ 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! Block: " << block_to_remove->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);
+
+ // If needed, remove the parameter dependencies on this residual block.
+ if (options_.enable_fast_parameter_block_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);
+ }
+ }
+ DeleteBlockInVector(program_->mutable_residual_blocks(), residual_block);
+}
+
+void ProblemImpl::RemoveParameterBlock(double* values) {
+ ParameterBlock* parameter_block = FindOrDie(parameter_block_map_, values);
+
+ if (options_.enable_fast_parameter_block_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) {
+ RemoveResidualBlock(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) {
+ RemoveResidualBlock(residual_block);
+ // The parameter blocks are guaranteed unique.
+ break;
+ }
+ }
+ }
+ }
+ DeleteBlockInVector(program_->mutable_parameter_blocks(), parameter_block);
+}
+
void ProblemImpl::SetParameterBlockConstant(double* values) {
FindOrDie(parameter_block_map_, values)->SetConstant();
}
@@ -338,6 +517,164 @@ void ProblemImpl::SetParameterization(
->SetParameterization(local_parameterization);
}
+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] =
+ FindOrDie(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();
+ }
+ 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;
+ bool status = evaluator->Evaluate(parameters.data(),
+ &tmp_cost,
+ residuals != NULL ? &(*residuals)[0] : NULL,
+ gradient != NULL ? &(*gradient)[0] : NULL,
+ tmp_jacobian.get());
+
+ // Make the parameter blocks that were temporarirly 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);
+ }
+ }
+
+ return status;
+}
+
int ProblemImpl::NumParameterBlocks() const {
return program_->NumParameterBlocks();
}
diff --git a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h
index 2ca055448c3..ccc315de6b6 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/problem_impl.h
@@ -53,6 +53,7 @@ namespace ceres {
class CostFunction;
class LossFunction;
class LocalParameterization;
+struct CRSMatrix;
namespace internal {
@@ -93,14 +94,46 @@ class ProblemImpl {
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);
+
+ 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;
@@ -112,12 +145,41 @@ class ProblemImpl {
const ParameterMap& parameter_map() const { return parameter_block_map_; }
private:
+ ParameterBlock* InternalAddParameterBlock(double* values, int size);
+
+ 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_;
+ // 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);
};
diff --git a/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h b/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h
index 6c48e7d7643..a19cdf8a86a 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/program_evaluator.h
@@ -83,11 +83,14 @@
#include <omp.h>
#endif
+#include <map>
+#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/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
namespace ceres {
namespace internal {
@@ -122,6 +125,12 @@ class ProgramEvaluator : public Evaluator {
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;
@@ -129,7 +138,7 @@ class ProgramEvaluator : public Evaluator {
if (residuals != NULL) {
VectorRef(residuals, program_->NumResiduals()).setZero();
- }
+ }
if (jacobian != NULL) {
jacobian->SetZero();
@@ -138,6 +147,10 @@ class ProgramEvaluator : public Evaluator {
// 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
@@ -262,6 +275,14 @@ class ProgramEvaluator : public Evaluator {
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 {
@@ -327,6 +348,7 @@ class ProgramEvaluator : public Evaluator {
scoped_array<EvaluatePreparer> evaluate_preparers_;
scoped_array<EvaluateScratch> evaluate_scratch_;
vector<int> residual_layout_;
+ ::ceres::internal::ExecutionSummary execution_summary_;
};
} // namespace internal
diff --git a/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc b/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc
index bdb88b1dd97..7f789605e5f 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/residual_block.cc
@@ -49,12 +49,14 @@ namespace internal {
ResidualBlock::ResidualBlock(const CostFunction* cost_function,
const LossFunction* loss_function,
- const vector<ParameterBlock*>& parameter_blocks)
+ 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()]) {
+ cost_function->parameter_block_sizes().size()]),
+ index_(index) {
std::copy(parameter_blocks.begin(),
parameter_blocks.end(),
parameter_blocks_.get());
diff --git a/extern/libmv/third_party/ceres/internal/ceres/residual_block.h b/extern/libmv/third_party/ceres/internal/ceres/residual_block.h
index e0a06e78958..3921d1d4678 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/residual_block.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/residual_block.h
@@ -34,11 +34,13 @@
#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 {
@@ -64,9 +66,13 @@ class ParameterBlock;
// 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);
+ 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
@@ -112,10 +118,23 @@ class ResidualBlock {
// 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
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
index 9442bb2a1c1..4d88a9f4f8a 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/residual_block_utils.cc
@@ -63,7 +63,8 @@ void InvalidateEvaluation(const ResidualBlock& block,
// 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.
-static void AppendArrayToString(const int size, const double* x, string* result) {
+namespace {
+void AppendArrayToString(const int size, const double* x, string* result) {
for (int i = 0; i < size; ++i) {
if (x == NULL) {
StringAppendF(result, "Not Computed ");
@@ -76,6 +77,7 @@ static void AppendArrayToString(const int size, const double* x, string* result)
}
}
}
+} // namespace
string EvaluationToString(const ResidualBlock& block,
double const* const* parameters,
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
index 2cbe78d133a..17537596c75 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.cc
@@ -38,22 +38,21 @@
#endif // CERES_NO_CXSPARSE
#include "Eigen/Dense"
-#include "glog/logging.h"
#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/detect_structure.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+#include "ceres/internal/scoped_ptr.h"
#include "ceres/linear_solver.h"
#include "ceres/schur_complement_solver.h"
#include "ceres/suitesparse.h"
#include "ceres/triplet_sparse_matrix.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/types.h"
-
+#include "ceres/wall_time.h"
namespace ceres {
namespace internal {
@@ -63,43 +62,39 @@ LinearSolver::Summary SchurComplementSolver::SolveImpl(
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double* x) {
- const time_t start_time = time(NULL);
+ EventLogger event_logger("SchurComplementSolver::Solve");
+
if (eliminator_.get() == NULL) {
InitStorage(A->block_structure());
DetectStructure(*A->block_structure(),
- options_.num_eliminate_blocks,
+ 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_.num_eliminate_blocks, A->block_structure());
+ eliminator_->Init(options_.elimination_groups[0], A->block_structure());
};
- const time_t init_time = time(NULL);
fill(x, x + A->num_cols(), 0.0);
+ event_logger.AddEvent("Setup");
LinearSolver::Summary summary;
summary.num_iterations = 1;
summary.termination_type = FAILURE;
eliminator_->Eliminate(A, b, per_solve_options.D, lhs_.get(), rhs_.get());
- const time_t eliminate_time = time(NULL);
+ event_logger.AddEvent("Eliminate");
double* reduced_solution = x + A->num_cols() - lhs_->num_cols();
const bool status = SolveReducedLinearSystem(reduced_solution);
- const time_t solve_time = time(NULL);
+ event_logger.AddEvent("ReducedSolve");
if (!status) {
return summary;
}
eliminator_->BackSubstitute(A, b, per_solve_options.D, reduced_solution, x);
- const time_t backsubstitute_time = time(NULL);
summary.termination_type = TOLERANCE;
- VLOG(2) << "time (sec) total: " << (backsubstitute_time - start_time)
- << " init: " << (init_time - start_time)
- << " eliminate: " << (eliminate_time - init_time)
- << " solve: " << (solve_time - eliminate_time)
- << " backsubstitute: " << (backsubstitute_time - solve_time);
+ event_logger.AddEvent("BackSubstitute");
return summary;
}
@@ -107,7 +102,7 @@ LinearSolver::Summary SchurComplementSolver::SolveImpl(
// complement.
void DenseSchurComplementSolver::InitStorage(
const CompressedRowBlockStructure* bs) {
- const int num_eliminate_blocks = options().num_eliminate_blocks;
+ 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);
@@ -179,7 +174,7 @@ SparseSchurComplementSolver::~SparseSchurComplementSolver() {
// initialize a BlockRandomAccessSparseMatrix object.
void SparseSchurComplementSolver::InitStorage(
const CompressedRowBlockStructure* bs) {
- const int num_eliminate_blocks = options().num_eliminate_blocks;
+ 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();
@@ -268,8 +263,6 @@ bool SparseSchurComplementSolver::SolveReducedLinearSystem(double* solution) {
// CHOLMOD's sparse cholesky factorization routines.
bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
double* solution) {
- const time_t start_time = time(NULL);
-
TripletSparseMatrix* tsm =
const_cast<TripletSparseMatrix*>(
down_cast<const BlockRandomAccessSparseMatrix*>(lhs())->matrix());
@@ -286,11 +279,9 @@ bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
// The matrix is symmetric, and the upper triangular part of the
// matrix contains the values.
cholmod_lhs->stype = 1;
- const time_t lhs_time = time(NULL);
cholmod_dense* cholmod_rhs =
ss_.CreateDenseVector(const_cast<double*>(rhs()), num_rows, num_rows);
- const time_t rhs_time = time(NULL);
// Symbolic factorization is computed if we don't already have one handy.
if (factor_ == NULL) {
@@ -307,32 +298,22 @@ bool SparseSchurComplementSolver::SolveReducedLinearSystemUsingSuiteSparse(
CHECK_NOTNULL(factor_);
- const time_t symbolic_time = time(NULL);
cholmod_dense* cholmod_solution =
ss_.SolveCholesky(cholmod_lhs, factor_, cholmod_rhs);
- const time_t solve_time = time(NULL);
-
ss_.Free(cholmod_lhs);
cholmod_lhs = NULL;
ss_.Free(cholmod_rhs);
cholmod_rhs = NULL;
if (cholmod_solution == NULL) {
- LOG(ERROR) << "CHOLMOD solve failed.";
+ LOG(WARNING) << "CHOLMOD solve failed.";
return false;
}
VectorRef(solution, num_rows)
= VectorRef(static_cast<double*>(cholmod_solution->x), num_rows);
ss_.Free(cholmod_solution);
- const time_t final_time = time(NULL);
- VLOG(2) << "time: " << (final_time - start_time)
- << " lhs : " << (lhs_time - start_time)
- << " rhs: " << (rhs_time - lhs_time)
- << " analyze: " << (symbolic_time - rhs_time)
- << " factor_and_solve: " << (solve_time - symbolic_time)
- << " cleanup: " << (final_time - solve_time);
return true;
}
#else
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
index ea1b3184c33..7e98f316255 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/schur_complement_solver.h
@@ -33,6 +33,7 @@
#include <set>
#include <utility>
+#include <vector>
#include "ceres/block_random_access_matrix.h"
#include "ceres/block_sparse_matrix.h"
@@ -97,13 +98,14 @@ class BlockSparseMatrixBase;
// The two solvers can be instantiated by calling
// LinearSolver::CreateLinearSolver with LinearSolver::Options::type
// set to DENSE_SCHUR and SPARSE_SCHUR
-// respectively. LinearSolver::Options::num_eliminate_blocks should be
+// respectively. LinearSolver::Options::elimination_groups[0] should be
// at least 1.
class SchurComplementSolver : public BlockSparseMatrixBaseSolver {
public:
explicit SchurComplementSolver(const LinearSolver::Options& options)
: options_(options) {
- CHECK_GT(options.num_eliminate_blocks, 0);
+ CHECK_GT(options.elimination_groups.size(), 1);
+ CHECK_GT(options.elimination_groups[0], 0);
}
// LinearSolver methods
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
index 6120db9b009..339c44bc41c 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/schur_eliminator_impl.h
@@ -50,7 +50,6 @@
#include <algorithm>
#include <map>
-#include <glog/logging.h>
#include "Eigen/Dense"
#include "ceres/block_random_access_matrix.h"
#include "ceres/block_sparse_matrix.h"
@@ -60,6 +59,7 @@
#include "ceres/stl_util.h"
#include "ceres/internal/eigen.h"
#include "ceres/internal/scoped_ptr.h"
+#include "glog/logging.h"
namespace ceres {
namespace internal {
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
new file mode 100644
index 00000000000..33a666ed037
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc
@@ -0,0 +1,145 @@
+// 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 "Eigen/Dense"
+#include "ceres/block_random_access_sparse_matrix.h"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/collections_port.h"
+#include "ceres/detect_structure.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.";
+
+ block_size_.resize(num_blocks);
+ set<pair<int, int> > block_pairs;
+
+ int num_block_diagonal_entries = 0;
+ for (int i = 0; i < num_blocks; ++i) {
+ block_size_[i] = bs.cols[i + options_.elimination_groups[0]].size;
+ block_pairs.insert(make_pair(i, i));
+ num_block_diagonal_entries += block_size_[i] * block_size_[i];
+ }
+
+ m_.reset(new BlockRandomAccessSparseMatrix(block_size_, block_pairs));
+ 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;
+
+ DetectStructure(bs, options_.elimination_groups[0],
+ &eliminator_options.row_block_size,
+ &eliminator_options.e_block_size,
+ &eliminator_options.f_block_size);
+
+ eliminator_.reset(SchurEliminatorBase::Create(eliminator_options));
+ eliminator_->Init(options_.elimination_groups[0], &bs);
+}
+
+// Update the values of the preconditioner matrix and factorize it.
+bool SchurJacobiPreconditioner::Update(const BlockSparseMatrixBase& 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());
+ return true;
+}
+
+void SchurJacobiPreconditioner::RightMultiply(const double* x,
+ double* y) const {
+ CHECK_NOTNULL(x);
+ CHECK_NOTNULL(y);
+
+ const double* lhs_values =
+ down_cast<BlockRandomAccessSparseMatrix*>(m_.get())->matrix()->values();
+
+ // This loop can be easily multi-threaded with OpenMP if need be.
+ for (int i = 0; i < block_size_.size(); ++i) {
+ const int block_size = block_size_[i];
+ ConstMatrixRef block(lhs_values, block_size, block_size);
+
+ VectorRef(y, block_size) =
+ block
+ .selfadjointView<Eigen::Upper>()
+ .ldlt()
+ .solve(ConstVectorRef(x, block_size));
+
+ x += block_size;
+ y += block_size;
+ lhs_values += block_size * block_size;
+ }
+}
+
+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
new file mode 100644
index 00000000000..3addd73abd2
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h
@@ -0,0 +1,110 @@
+// 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 BlockRandomAccessSparseMatrix;
+class BlockSparseMatrixBase;
+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 Preconditioner {
+ 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 bool Update(const BlockSparseMatrixBase& A, const double* D);
+ virtual void RightMultiply(const double* x, double* y) const;
+ virtual int num_rows() const;
+
+ private:
+ void InitEliminator(const CompressedRowBlockStructure& bs);
+
+ Preconditioner::Options options_;
+
+ // Sizes of the blocks in the schur complement.
+ vector<int> block_size_;
+ scoped_ptr<SchurEliminatorBase> eliminator_;
+
+ // Preconditioner matrix.
+ scoped_ptr<BlockRandomAccessSparseMatrix> 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/solver.cc b/extern/libmv/third_party/ceres/internal/ceres/solver.cc
index 66ca93283a1..6436d2df2a7 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/solver.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/solver.cc
@@ -37,20 +37,41 @@
#include "ceres/program.h"
#include "ceres/solver_impl.h"
#include "ceres/stringprintf.h"
+#include "ceres/wall_time.h"
namespace ceres {
+namespace {
+
+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());
+}
+
+} // namespace
+
+Solver::Options::~Options() {
+ delete linear_solver_ordering;
+ delete inner_iteration_ordering;
+}
Solver::~Solver() {}
-// TODO(sameeragarwal): Use subsecond timers.
void Solver::Solve(const Solver::Options& options,
Problem* problem,
Solver::Summary* summary) {
- time_t start_time_seconds = time(NULL);
+ double start_time_seconds = internal::WallTimeInSeconds();
internal::ProblemImpl* problem_impl =
CHECK_NOTNULL(problem)->problem_impl_.get();
internal::SolverImpl::Solve(options, problem_impl, summary);
- summary->total_time_in_seconds = time(NULL) - start_time_seconds;
+ summary->total_time_in_seconds =
+ internal::WallTimeInSeconds() - start_time_seconds;
}
void Solve(const Solver::Options& options,
@@ -63,7 +84,8 @@ void Solve(const Solver::Options& options,
Solver::Summary::Summary()
// Invalid values for most fields, to ensure that we are not
// accidentally reporting default values.
- : termination_type(DID_NOT_RUN),
+ : minimizer_type(TRUST_REGION),
+ termination_type(DID_NOT_RUN),
initial_cost(-1.0),
final_cost(-1.0),
fixed_cost(-1.0),
@@ -73,6 +95,9 @@ Solver::Summary::Summary()
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),
num_parameter_blocks(-1),
num_parameters(-1),
num_residual_blocks(-1),
@@ -81,8 +106,6 @@ Solver::Summary::Summary()
num_parameters_reduced(-1),
num_residual_blocks_reduced(-1),
num_residuals_reduced(-1),
- num_eliminate_blocks_given(-1),
- num_eliminate_blocks_used(-1),
num_threads_given(-1),
num_threads_used(-1),
num_linear_solver_threads_given(-1),
@@ -90,9 +113,11 @@ Solver::Summary::Summary()
linear_solver_type_given(SPARSE_NORMAL_CHOLESKY),
linear_solver_type_used(SPARSE_NORMAL_CHOLESKY),
preconditioner_type(IDENTITY),
- ordering_type(NATURAL),
trust_region_strategy_type(LEVENBERG_MARQUARDT),
- sparse_linear_algebra_library(SUITE_SPARSE) {
+ inner_iterations(false),
+ sparse_linear_algebra_library(SUITE_SPARSE),
+ line_search_direction_type(LBFGS),
+ line_search_type(ARMIJO) {
}
string Solver::Summary::BriefReport() const {
@@ -121,6 +146,8 @@ string Solver::Summary::BriefReport() const {
return report;
};
+using internal::StringAppendF;
+
string Solver::Summary::FullReport() const {
string report =
"\n"
@@ -128,124 +155,210 @@ string Solver::Summary::FullReport() const {
"-------------------\n";
if (termination_type == DID_NOT_RUN) {
- internal::StringAppendF(&report, " Original\n");
- internal::StringAppendF(&report, "Parameter blocks % 10d\n",
- num_parameter_blocks);
- internal::StringAppendF(&report, "Parameters % 10d\n",
- num_parameters);
- internal::StringAppendF(&report, "Residual blocks % 10d\n",
- num_residual_blocks);
- internal::StringAppendF(&report, "Residuals % 10d\n\n",
- num_residuals);
+ StringAppendF(&report, " Original\n");
+ StringAppendF(&report, "Parameter blocks % 10d\n",
+ num_parameter_blocks);
+ StringAppendF(&report, "Parameters % 10d\n",
+ num_parameters);
+ StringAppendF(&report, "Residual blocks % 10d\n",
+ num_residual_blocks);
+ StringAppendF(&report, "Residuals % 10d\n\n",
+ num_residuals);
} else {
- internal::StringAppendF(&report, "%45s %21s\n", "Original", "Reduced");
- internal::StringAppendF(&report, "Parameter blocks % 25d% 25d\n",
- num_parameter_blocks, num_parameter_blocks_reduced);
- internal::StringAppendF(&report, "Parameters % 25d% 25d\n",
- num_parameters, num_parameters_reduced);
- internal::StringAppendF(&report, "Residual blocks % 25d% 25d\n",
- num_residual_blocks, num_residual_blocks_reduced);
- internal::StringAppendF(&report, "Residual % 25d% 25d\n\n",
- num_residuals, num_residuals_reduced);
+ 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);
+ 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);
}
- internal::StringAppendF(&report, "%45s %21s\n", "Given", "Used");
- internal::StringAppendF(&report, "Linear solver %25s%25s\n",
- LinearSolverTypeToString(linear_solver_type_given),
- LinearSolverTypeToString(linear_solver_type_used));
+ // TODO(sameeragarwal): Refactor this into separate functions.
- if (linear_solver_type_given == CGNR ||
- linear_solver_type_given == ITERATIVE_SCHUR) {
- internal::StringAppendF(&report, "Preconditioner %25s%25s\n",
- PreconditionerTypeToString(preconditioner_type),
- PreconditionerTypeToString(preconditioner_type));
- } else {
- internal::StringAppendF(&report, "Preconditioner %25s%25s\n",
- "N/A", "N/A");
- }
+ if (minimizer_type == TRUST_REGION) {
+ StringAppendF(&report, "\nMinimizer %19s\n",
+ "TRUST_REGION");
+ if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY ||
+ linear_solver_type_used == SPARSE_SCHUR ||
+ (linear_solver_type_used == ITERATIVE_SCHUR &&
+ (preconditioner_type == CLUSTER_JACOBI ||
+ preconditioner_type == CLUSTER_TRIDIAGONAL))) {
+ StringAppendF(&report, "\nSparse Linear Algebra Library %15s\n",
+ SparseLinearAlgebraLibraryTypeToString(
+ sparse_linear_algebra_library));
+ }
- internal::StringAppendF(&report, "Ordering %25s%25s\n",
- OrderingTypeToString(ordering_type),
- OrderingTypeToString(ordering_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 (IsSchurType(linear_solver_type_given)) {
- if (ordering_type == SCHUR) {
- internal::StringAppendF(&report, "num_eliminate_blocks%25s% 25d\n",
- "N/A",
- num_eliminate_blocks_used);
+ if (linear_solver_type_given == CGNR ||
+ linear_solver_type_given == ITERATIVE_SCHUR) {
+ StringAppendF(&report, "Preconditioner %25s%25s\n",
+ PreconditionerTypeToString(preconditioner_type),
+ PreconditionerTypeToString(preconditioner_type));
} else {
- internal::StringAppendF(&report, "num_eliminate_blocks% 25d% 25d\n",
- num_eliminate_blocks_given,
- num_eliminate_blocks_used);
+ StringAppendF(&report, "Preconditioner %25s%25s\n",
+ "N/A", "N/A");
}
- }
- internal::StringAppendF(&report, "Threads: % 25d% 25d\n",
- num_threads_given, num_threads_used);
- internal::StringAppendF(&report, "Linear solver threads % 23d% 25d\n",
- num_linear_solver_threads_given,
- num_linear_solver_threads_used);
-
- if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY ||
- linear_solver_type_used == SPARSE_SCHUR ||
- (linear_solver_type_used == ITERATIVE_SCHUR &&
- (preconditioner_type == SCHUR_JACOBI ||
- preconditioner_type == CLUSTER_JACOBI ||
- preconditioner_type == CLUSTER_TRIDIAGONAL))) {
- internal::StringAppendF(&report, "\nSparse Linear Algebra Library %15s\n",
- SparseLinearAlgebraLibraryTypeToString(
- sparse_linear_algebra_library));
- }
+ 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) {
+ 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());
+ }
+
+ if (termination_type == DID_NOT_RUN) {
+ CHECK(!error.empty())
+ << "Solver terminated with DID_NOT_RUN but the solver did not "
+ << "return a reason. This is a Ceres error. Please report this "
+ << "to the Ceres team";
+ StringAppendF(&report, "Termination: %20s\n",
+ "DID_NOT_RUN");
+ StringAppendF(&report, "Reason: %s\n", error.c_str());
+ return report;
+ }
+
+ StringAppendF(&report, "\nCost:\n");
+ StringAppendF(&report, "Initial % 30e\n", initial_cost);
+ if (termination_type != NUMERICAL_FAILURE &&
+ termination_type != USER_ABORT) {
+ StringAppendF(&report, "Final % 30e\n", final_cost);
+ StringAppendF(&report, "Change % 30e\n",
+ initial_cost - final_cost);
+ }
+
+ StringAppendF(&report, "\nNumber of iterations:\n");
+ StringAppendF(&report, "Successful % 20d\n",
+ num_successful_steps);
+ StringAppendF(&report, "Unsuccessful % 20d\n",
+ num_unsuccessful_steps);
+ StringAppendF(&report, "Total % 20d\n",
+ num_successful_steps + num_unsuccessful_steps);
+
+ StringAppendF(&report, "\nTime (in seconds):\n");
+ StringAppendF(&report, "Preprocessor %25.3f\n",
+ preprocessor_time_in_seconds);
+ StringAppendF(&report, "\n Residual Evaluations %22.3f\n",
+ residual_evaluation_time_in_seconds);
+ StringAppendF(&report, " Jacobian Evaluations %22.3f\n",
+ jacobian_evaluation_time_in_seconds);
+ StringAppendF(&report, " Linear Solver %23.3f\n",
+ linear_solver_time_in_seconds);
+ StringAppendF(&report, "Minimizer %25.3f\n\n",
+ minimizer_time_in_seconds);
+
+ StringAppendF(&report, "Postprocessor %24.3f\n",
+ postprocessor_time_in_seconds);
- internal::StringAppendF(&report, "Trust Region Strategy %19s",
- TrustRegionStrategyTypeToString(
- trust_region_strategy_type));
- if (trust_region_strategy_type == DOGLEG) {
- if (dogleg_type == TRADITIONAL_DOGLEG) {
- internal::StringAppendF(&report, " (TRADITIONAL)");
+ StringAppendF(&report, "Total %25.3f\n\n",
+ total_time_in_seconds);
+
+ StringAppendF(&report, "Termination: %25s\n",
+ SolverTerminationTypeToString(termination_type));
+ } else {
+ // LINE_SEARCH
+ StringAppendF(&report, "\nMinimizer %19s\n", "LINE_SEARCH");
+ if (line_search_direction_type == LBFGS) {
+ StringAppendF(&report, "Line search direction %19s(%d)\n",
+ LineSearchDirectionTypeToString(line_search_direction_type),
+ max_lbfgs_rank);
} else {
- internal::StringAppendF(&report, " (SUBSPACE)");
+ StringAppendF(&report, "Line search direction %19s\n",
+ LineSearchDirectionTypeToString(
+ line_search_direction_type));
}
- }
- internal::StringAppendF(&report, "\n");
+ StringAppendF(&report, "Line search type %19s\n",
+ LineSearchTypeToString(line_search_type));
+ StringAppendF(&report, "\n");
- if (termination_type == DID_NOT_RUN) {
- CHECK(!error.empty())
- << "Solver terminated with DID_NOT_RUN but the solver did not "
- << "return a reason. This is a Ceres error. Please report this "
- << "to the Ceres team";
- internal::StringAppendF(&report, "Termination: %20s\n",
- "DID_NOT_RUN");
- internal::StringAppendF(&report, "Reason: %s\n", error.c_str());
- return report;
- }
+ StringAppendF(&report, "%45s %21s\n", "Given", "Used");
+ StringAppendF(&report, "Threads: % 25d% 25d\n",
+ num_threads_given, num_threads_used);
- internal::StringAppendF(&report, "\nCost:\n");
- internal::StringAppendF(&report, "Initial % 30e\n", initial_cost);
- if (termination_type != NUMERICAL_FAILURE && termination_type != USER_ABORT) {
- internal::StringAppendF(&report, "Final % 30e\n", final_cost);
- internal::StringAppendF(&report, "Change % 30e\n",
- initial_cost - final_cost);
+ if (termination_type == DID_NOT_RUN) {
+ CHECK(!error.empty())
+ << "Solver terminated with DID_NOT_RUN but the solver did not "
+ << "return a reason. This is a Ceres error. Please report this "
+ << "to the Ceres team";
+ StringAppendF(&report, "Termination: %20s\n",
+ "DID_NOT_RUN");
+ StringAppendF(&report, "Reason: %s\n", error.c_str());
+ return report;
+ }
+
+ StringAppendF(&report, "\nCost:\n");
+ StringAppendF(&report, "Initial % 30e\n", initial_cost);
+ if (termination_type != NUMERICAL_FAILURE &&
+ termination_type != USER_ABORT) {
+ StringAppendF(&report, "Final % 30e\n", final_cost);
+ StringAppendF(&report, "Change % 30e\n",
+ initial_cost - final_cost);
+ }
+
+ StringAppendF(&report, "\nNumber of iterations: % 20ld\n",
+ iterations.size() - 1);
+
+ StringAppendF(&report, "\nTime (in seconds):\n");
+ StringAppendF(&report, "Preprocessor %25.3f\n",
+ preprocessor_time_in_seconds);
+ StringAppendF(&report, "\n Residual Evaluations %22.3f\n",
+ residual_evaluation_time_in_seconds);
+ StringAppendF(&report, " Jacobian Evaluations %22.3f\n",
+ jacobian_evaluation_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\n",
+ SolverTerminationTypeToString(termination_type));
}
- internal::StringAppendF(&report, "\nNumber of iterations:\n");
- internal::StringAppendF(&report, "Successful % 20d\n",
- num_successful_steps);
- internal::StringAppendF(&report, "Unsuccessful % 20d\n",
- num_unsuccessful_steps);
- internal::StringAppendF(&report, "Total % 20d\n",
- num_successful_steps + num_unsuccessful_steps);
- internal::StringAppendF(&report, "\nTime (in seconds):\n");
- internal::StringAppendF(&report, "Preprocessor % 25e\n",
- preprocessor_time_in_seconds);
- internal::StringAppendF(&report, "Minimizer % 25e\n",
- minimizer_time_in_seconds);
- internal::StringAppendF(&report, "Total % 25e\n",
- total_time_in_seconds);
-
- internal::StringAppendF(&report, "Termination: %25s\n",
- SolverTerminationTypeToString(termination_type));
return report;
};
diff --git a/extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc b/extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc
index 8ef5b98e35f..5bcfdc6312f 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/solver_impl.cc
@@ -33,21 +33,25 @@
#include <cstdio>
#include <iostream> // NOLINT
#include <numeric>
+#include "ceres/coordinate_descent_minimizer.h"
#include "ceres/evaluator.h"
#include "ceres/gradient_checking_cost_function.h"
#include "ceres/iteration_callback.h"
#include "ceres/levenberg_marquardt_strategy.h"
#include "ceres/linear_solver.h"
+#include "ceres/line_search_minimizer.h"
#include "ceres/map_util.h"
#include "ceres/minimizer.h"
+#include "ceres/ordered_groups.h"
#include "ceres/parameter_block.h"
+#include "ceres/parameter_block_ordering.h"
#include "ceres/problem.h"
#include "ceres/problem_impl.h"
#include "ceres/program.h"
#include "ceres/residual_block.h"
-#include "ceres/schur_ordering.h"
#include "ceres/stringprintf.h"
#include "ceres/trust_region_minimizer.h"
+#include "ceres/wall_time.h"
namespace ceres {
namespace internal {
@@ -73,14 +77,24 @@ class StateUpdatingCallback : public IterationCallback {
double* parameters_;
};
+void SetSummaryFinalCost(Solver::Summary* 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);
+ }
+}
+
// 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 {
+class TrustRegionLoggingCallback : public IterationCallback {
public:
- explicit LoggingCallback(bool log_to_stdout)
+ explicit TrustRegionLoggingCallback(bool log_to_stdout)
: log_to_stdout_(log_to_stdout) {}
- ~LoggingCallback() {}
+ ~TrustRegionLoggingCallback() {}
CallbackReturnType operator()(const IterationSummary& summary) {
const char* kReportRowFormat =
@@ -109,6 +123,42 @@ class LoggingCallback : public IterationCallback {
const bool log_to_stdout_;
};
+// Callback for logging the state of the minimizer to STDERR or STDOUT
+// depending on the user's preferences and logging level.
+class LineSearchLoggingCallback : public IterationCallback {
+ public:
+ explicit LineSearchLoggingCallback(bool log_to_stdout)
+ : log_to_stdout_(log_to_stdout) {}
+
+ ~LineSearchLoggingCallback() {}
+
+ CallbackReturnType operator()(const IterationSummary& summary) {
+ 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";
+ string 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);
+ if (log_to_stdout_) {
+ cout << output << endl;
+ } else {
+ VLOG(1) << output;
+ }
+ return SOLVER_CONTINUE;
+ }
+
+ private:
+ const bool log_to_stdout_;
+};
+
+
// Basic callback to record the execution of the solver to a file for
// offline analysis.
class FileLoggingCallback : public IterationCallback {
@@ -137,14 +187,34 @@ class FileLoggingCallback : public IterationCallback {
FILE* fptr_;
};
+// Iterate over each of the groups in order of their priority and fill
+// summary with their sizes.
+void SummarizeOrdering(ParameterBlockOrdering* ordering,
+ vector<int>* summary) {
+ CHECK_NOTNULL(summary)->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) {
+ summary->push_back(it->second.size());
+ }
+}
+
} // namespace
-void SolverImpl::Minimize(const Solver::Options& options,
- Program* program,
- Evaluator* evaluator,
- LinearSolver* linear_solver,
- double* parameters,
- Solver::Summary* summary) {
+void SolverImpl::TrustRegionMinimize(
+ const Solver::Options& options,
+ Program* program,
+ CoordinateDescentMinimizer* inner_iteration_minimizer,
+ Evaluator* evaluator,
+ LinearSolver* linear_solver,
+ double* parameters,
+ Solver::Summary* summary) {
Minimizer::Options minimizer_options(options);
// TODO(sameeragarwal): Add support for logging the configuration
@@ -156,7 +226,8 @@ void SolverImpl::Minimize(const Solver::Options& options,
file_logging_callback.get());
}
- LoggingCallback logging_callback(options.minimizer_progress_to_stdout);
+ TrustRegionLoggingCallback logging_callback(
+ options.minimizer_progress_to_stdout);
if (options.logging_type != SILENT) {
minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
&logging_callback);
@@ -172,7 +243,9 @@ void SolverImpl::Minimize(const Solver::Options& options,
minimizer_options.evaluator = evaluator;
scoped_ptr<SparseMatrix> jacobian(evaluator->CreateJacobian());
+
minimizer_options.jacobian = jacobian.get();
+ minimizer_options.inner_iteration_minimizer = inner_iteration_minimizer;
TrustRegionStrategy::Options trust_region_strategy_options;
trust_region_strategy_options.linear_solver = linear_solver;
@@ -189,78 +262,140 @@ void SolverImpl::Minimize(const Solver::Options& options,
minimizer_options.trust_region_strategy = strategy.get();
TrustRegionMinimizer minimizer;
- time_t minimizer_start_time = time(NULL);
+ double minimizer_start_time = WallTimeInSeconds();
minimizer.Minimize(minimizer_options, parameters, summary);
- summary->minimizer_time_in_seconds = time(NULL) - minimizer_start_time;
+ summary->minimizer_time_in_seconds =
+ WallTimeInSeconds() - minimizer_start_time;
}
-void SolverImpl::Solve(const Solver::Options& original_options,
- ProblemImpl* original_problem_impl,
+
+void SolverImpl::LineSearchMinimize(
+ const Solver::Options& options,
+ Program* program,
+ Evaluator* evaluator,
+ double* parameters,
+ Solver::Summary* summary) {
+ Minimizer::Options minimizer_options(options);
+
+ // TODO(sameeragarwal): Add support for logging the configuration
+ // and more detailed stats.
+ scoped_ptr<IterationCallback> file_logging_callback;
+ if (!options.solver_log.empty()) {
+ file_logging_callback.reset(new FileLoggingCallback(options.solver_log));
+ minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
+ file_logging_callback.get());
+ }
+
+ LineSearchLoggingCallback logging_callback(
+ options.minimizer_progress_to_stdout);
+ if (options.logging_type != SILENT) {
+ minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
+ &logging_callback);
+ }
+
+ StateUpdatingCallback updating_callback(program, parameters);
+ if (options.update_state_every_iteration) {
+ // 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(),
+ &updating_callback);
+ }
+
+ minimizer_options.evaluator = evaluator;
+
+ LineSearchMinimizer minimizer;
+ double minimizer_start_time = WallTimeInSeconds();
+ minimizer.Minimize(minimizer_options, parameters, summary);
+ summary->minimizer_time_in_seconds =
+ WallTimeInSeconds() - minimizer_start_time;
+}
+
+void SolverImpl::Solve(const Solver::Options& options,
+ ProblemImpl* problem_impl,
Solver::Summary* summary) {
- time_t solver_start_time = time(NULL);
- Solver::Options options(original_options);
+ if (options.minimizer_type == TRUST_REGION) {
+ TrustRegionSolve(options, problem_impl, summary);
+ } else {
+ LineSearchSolve(options, problem_impl, summary);
+ }
+}
+
+void SolverImpl::TrustRegionSolve(const Solver::Options& original_options,
+ ProblemImpl* original_problem_impl,
+ Solver::Summary* summary) {
+ EventLogger event_logger("TrustRegionSolve");
+ double solver_start_time = WallTimeInSeconds();
+
Program* original_program = original_problem_impl->mutable_program();
ProblemImpl* problem_impl = original_problem_impl;
+
// Reset the summary object to its default values.
*CHECK_NOTNULL(summary) = Solver::Summary();
+ summary->minimizer_type = TRUST_REGION;
+ summary->num_parameter_blocks = problem_impl->NumParameterBlocks();
+ summary->num_parameters = problem_impl->NumParameters();
+ summary->num_residual_blocks = problem_impl->NumResidualBlocks();
+ summary->num_residuals = problem_impl->NumResiduals();
+
+ // Empty programs are usually a user error.
+ if (summary->num_parameter_blocks == 0) {
+ summary->error = "Problem contains no parameter blocks.";
+ LOG(ERROR) << summary->error;
+ return;
+ }
+
+ if (summary->num_residual_blocks == 0) {
+ summary->error = "Problem contains no residual blocks.";
+ LOG(ERROR) << summary->error;
+ return;
+ }
+
+ SummarizeOrdering(original_options.linear_solver_ordering,
+ &(summary->linear_solver_ordering_given));
+
+ SummarizeOrdering(original_options.inner_iteration_ordering,
+ &(summary->inner_iteration_ordering_given));
+
+ Solver::Options options(original_options);
+ options.linear_solver_ordering = NULL;
+ options.inner_iteration_ordering = NULL;
#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"
+ << "only options.num_threads=1 is supported. Switching "
<< "to single threaded mode.";
options.num_threads = 1;
}
if (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"
+ << "only options.num_linear_solver_threads=1 is supported. Switching "
<< "to single threaded mode.";
options.num_linear_solver_threads = 1;
}
#endif
- summary->linear_solver_type_given = options.linear_solver_type;
- summary->num_eliminate_blocks_given = original_options.num_eliminate_blocks;
summary->num_threads_given = original_options.num_threads;
- summary->num_linear_solver_threads_given =
- original_options.num_linear_solver_threads;
- summary->ordering_type = original_options.ordering_type;
+ summary->num_threads_used = options.num_threads;
- summary->num_parameter_blocks = problem_impl->NumParameterBlocks();
- summary->num_parameters = problem_impl->NumParameters();
- summary->num_residual_blocks = problem_impl->NumResidualBlocks();
- summary->num_residuals = problem_impl->NumResiduals();
+ if (options.lsqp_iterations_to_dump.size() > 0) {
+ LOG(WARNING) << "Dumping linear least squares problems to disk is"
+ " currently broken. Ignoring Solver::Options::lsqp_iterations_to_dump";
+ }
- summary->num_threads_used = options.num_threads;
- summary->sparse_linear_algebra_library =
- options.sparse_linear_algebra_library;
- summary->trust_region_strategy_type = options.trust_region_strategy_type;
- summary->dogleg_type = options.dogleg_type;
+ event_logger.AddEvent("Init");
- // Evaluate the initial cost, residual vector and the jacobian
- // matrix if requested by the user. The initial cost needs to be
- // computed on the original unpreprocessed problem, as it is used to
- // determine the value of the "fixed" part of the objective function
- // after the problem has undergone reduction.
- Evaluator::Evaluate(
- original_program,
- options.num_threads,
- &(summary->initial_cost),
- options.return_initial_residuals ? &summary->initial_residuals : NULL,
- options.return_initial_gradient ? &summary->initial_gradient : NULL,
- options.return_initial_jacobian ? &summary->initial_jacobian : NULL);
- original_program->SetParameterBlockStatePtrsToUserStatePtrs();
+ original_program->SetParameterBlockStatePtrsToUserStatePtrs();
+ event_logger.AddEvent("SetParameterBlockPtrs");
// If the user requests gradient checking, construct a new
// ProblemImpl by wrapping the CostFunctions of problem_impl inside
// GradientCheckingCostFunction and replacing problem_impl with
// gradient_checking_problem_impl.
scoped_ptr<ProblemImpl> gradient_checking_problem_impl;
- // Save the original problem impl so we don't use the gradient
- // checking one when computing the residuals.
if (options.check_gradients) {
VLOG(1) << "Checking Gradients";
gradient_checking_problem_impl.reset(
@@ -269,45 +404,344 @@ void SolverImpl::Solve(const Solver::Options& original_options,
options.numeric_derivative_relative_step_size,
options.gradient_check_relative_precision));
- // From here on, problem_impl will point to the GradientChecking version.
+ // From here on, problem_impl will point to the gradient checking
+ // version.
problem_impl = gradient_checking_problem_impl.get();
}
+ if (original_options.linear_solver_ordering != NULL) {
+ if (!IsOrderingValid(original_options, problem_impl, &summary->error)) {
+ LOG(ERROR) << summary->error;
+ return;
+ }
+ event_logger.AddEvent("CheckOrdering");
+ options.linear_solver_ordering =
+ new ParameterBlockOrdering(*original_options.linear_solver_ordering);
+ event_logger.AddEvent("CopyOrdering");
+ } else {
+ options.linear_solver_ordering = new ParameterBlockOrdering;
+ const ProblemImpl::ParameterMap& parameter_map =
+ problem_impl->parameter_map();
+ for (ProblemImpl::ParameterMap::const_iterator it = parameter_map.begin();
+ it != parameter_map.end();
+ ++it) {
+ options.linear_solver_ordering->AddElementToGroup(it->first, 0);
+ }
+ event_logger.AddEvent("ConstructOrdering");
+ }
+
// Create the three objects needed to minimize: the transformed program, the
// evaluator, and the linear solver.
-
scoped_ptr<Program> reduced_program(CreateReducedProgram(&options,
problem_impl,
&summary->fixed_cost,
&summary->error));
+
+ event_logger.AddEvent("CreateReducedProgram");
if (reduced_program == NULL) {
return;
}
+ SummarizeOrdering(options.linear_solver_ordering,
+ &(summary->linear_solver_ordering_used));
+
summary->num_parameter_blocks_reduced = reduced_program->NumParameterBlocks();
summary->num_parameters_reduced = reduced_program->NumParameters();
summary->num_residual_blocks_reduced = reduced_program->NumResidualBlocks();
summary->num_residuals_reduced = reduced_program->NumResiduals();
+ if (summary->num_parameter_blocks_reduced == 0) {
+ summary->preprocessor_time_in_seconds =
+ WallTimeInSeconds() - solver_start_time;
+
+ double post_process_start_time = WallTimeInSeconds();
+ LOG(INFO) << "Terminating: FUNCTION_TOLERANCE reached. "
+ << "No non-constant parameter blocks found.";
+
+ summary->initial_cost = summary->fixed_cost;
+ summary->final_cost = summary->fixed_cost;
+
+ // FUNCTION_TOLERANCE is the right convergence here, as we know
+ // that the objective function is constant and cannot be changed
+ // any further.
+ summary->termination_type = FUNCTION_TOLERANCE;
+
+ // Ensure the program state is set to the user parameters on the way out.
+ original_program->SetParameterBlockStatePtrsToUserStatePtrs();
+
+ summary->postprocessor_time_in_seconds =
+ WallTimeInSeconds() - post_process_start_time;
+ return;
+ }
+
scoped_ptr<LinearSolver>
linear_solver(CreateLinearSolver(&options, &summary->error));
+ event_logger.AddEvent("CreateLinearSolver");
+ if (linear_solver == NULL) {
+ return;
+ }
+
+ summary->linear_solver_type_given = original_options.linear_solver_type;
summary->linear_solver_type_used = options.linear_solver_type;
+
summary->preconditioner_type = options.preconditioner_type;
- summary->num_eliminate_blocks_used = options.num_eliminate_blocks;
+
+ summary->num_linear_solver_threads_given =
+ original_options.num_linear_solver_threads;
summary->num_linear_solver_threads_used = options.num_linear_solver_threads;
- if (linear_solver == NULL) {
+ summary->sparse_linear_algebra_library =
+ options.sparse_linear_algebra_library;
+
+ summary->trust_region_strategy_type = options.trust_region_strategy_type;
+ summary->dogleg_type = options.dogleg_type;
+
+ // Only Schur types require the lexicographic reordering.
+ if (IsSchurType(options.linear_solver_type)) {
+ const int num_eliminate_blocks =
+ options.linear_solver_ordering
+ ->group_to_elements().begin()
+ ->second.size();
+ if (!LexicographicallyOrderResidualBlocks(num_eliminate_blocks,
+ reduced_program.get(),
+ &summary->error)) {
+ return;
+ }
+ }
+
+ scoped_ptr<Evaluator> evaluator(CreateEvaluator(options,
+ problem_impl->parameter_map(),
+ reduced_program.get(),
+ &summary->error));
+
+ event_logger.AddEvent("CreateEvaluator");
+
+ if (evaluator == NULL) {
+ return;
+ }
+
+ scoped_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer;
+ if (options.use_inner_iterations) {
+ if (reduced_program->parameter_blocks().size() < 2) {
+ LOG(WARNING) << "Reduced problem only contains one parameter block."
+ << "Disabling inner iterations.";
+ } else {
+ inner_iteration_minimizer.reset(
+ CreateInnerIterationMinimizer(original_options,
+ *reduced_program,
+ problem_impl->parameter_map(),
+ summary));
+ if (inner_iteration_minimizer == NULL) {
+ LOG(ERROR) << summary->error;
+ return;
+ }
+ }
+ }
+
+ event_logger.AddEvent("CreateIIM");
+
+ // The optimizer works on contiguous parameter vectors; allocate some.
+ Vector parameters(reduced_program->NumParameters());
+
+ // Collect the discontiguous parameters into a contiguous state vector.
+ reduced_program->ParameterBlocksToStateVector(parameters.data());
+
+ Vector original_parameters = parameters;
+
+ double minimizer_start_time = WallTimeInSeconds();
+ summary->preprocessor_time_in_seconds =
+ minimizer_start_time - solver_start_time;
+
+ // Run the optimization.
+ TrustRegionMinimize(options,
+ reduced_program.get(),
+ inner_iteration_minimizer.get(),
+ evaluator.get(),
+ linear_solver.get(),
+ parameters.data(),
+ summary);
+ event_logger.AddEvent("Minimize");
+
+ SetSummaryFinalCost(summary);
+
+ // If the user aborted mid-optimization or the optimization
+ // terminated because of a numerical failure, then return without
+ // updating user state.
+ if (summary->termination_type == USER_ABORT ||
+ summary->termination_type == NUMERICAL_FAILURE) {
return;
}
- if (!MaybeReorderResidualBlocks(options,
- reduced_program.get(),
- &summary->error)) {
+ double post_process_start_time = WallTimeInSeconds();
+
+ // Push the contiguous optimized parameters back to the user's
+ // parameters.
+ reduced_program->StateVectorToParameterBlocks(parameters.data());
+ reduced_program->CopyParameterBlockStateToUserState();
+
+ // Ensure the program state is set to the user parameters on the way
+ // out.
+ original_program->SetParameterBlockStatePtrsToUserStatePtrs();
+
+ const map<string, double>& linear_solver_time_statistics =
+ linear_solver->TimeStatistics();
+ summary->linear_solver_time_in_seconds =
+ FindWithDefault(linear_solver_time_statistics,
+ "LinearSolver::Solve",
+ 0.0);
+
+ const map<string, double>& evaluator_time_statistics =
+ 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);
+
+ // Stick a fork in it, we're done.
+ summary->postprocessor_time_in_seconds =
+ WallTimeInSeconds() - post_process_start_time;
+ event_logger.AddEvent("PostProcess");
+}
+
+void SolverImpl::LineSearchSolve(const Solver::Options& original_options,
+ ProblemImpl* original_problem_impl,
+ Solver::Summary* summary) {
+ double solver_start_time = WallTimeInSeconds();
+
+ Program* original_program = original_problem_impl->mutable_program();
+ ProblemImpl* problem_impl = original_problem_impl;
+
+ // Reset the summary object to its default values.
+ *CHECK_NOTNULL(summary) = Solver::Summary();
+
+ summary->minimizer_type = LINE_SEARCH;
+ summary->line_search_direction_type =
+ original_options.line_search_direction_type;
+ summary->max_lbfgs_rank = original_options.max_lbfgs_rank;
+ summary->line_search_type = original_options.line_search_type;
+ summary->num_parameter_blocks = problem_impl->NumParameterBlocks();
+ summary->num_parameters = problem_impl->NumParameters();
+ summary->num_residual_blocks = problem_impl->NumResidualBlocks();
+ summary->num_residuals = problem_impl->NumResiduals();
+
+ // Empty programs are usually a user error.
+ if (summary->num_parameter_blocks == 0) {
+ summary->error = "Problem contains no parameter blocks.";
+ LOG(ERROR) << summary->error;
return;
}
- scoped_ptr<Evaluator> evaluator(
- CreateEvaluator(options, reduced_program.get(), &summary->error));
+ if (summary->num_residual_blocks == 0) {
+ summary->error = "Problem contains no residual blocks.";
+ LOG(ERROR) << summary->error;
+ return;
+ }
+
+ Solver::Options options(original_options);
+
+ // This ensures that we get a Block Jacobian Evaluator along with
+ // none of the Schur nonsense. This file will have to be extensively
+ // refactored to deal with the various bits of cleanups related to
+ // line search.
+ options.linear_solver_type = CGNR;
+
+ options.linear_solver_ordering = NULL;
+ options.inner_iteration_ordering = NULL;
+
+#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
+
+ summary->num_threads_given = original_options.num_threads;
+ summary->num_threads_used = options.num_threads;
+
+ if (original_options.linear_solver_ordering != NULL) {
+ if (!IsOrderingValid(original_options, problem_impl, &summary->error)) {
+ LOG(ERROR) << summary->error;
+ return;
+ }
+ options.linear_solver_ordering =
+ new ParameterBlockOrdering(*original_options.linear_solver_ordering);
+ } else {
+ options.linear_solver_ordering = new ParameterBlockOrdering;
+ const ProblemImpl::ParameterMap& parameter_map =
+ problem_impl->parameter_map();
+ for (ProblemImpl::ParameterMap::const_iterator it = parameter_map.begin();
+ it != parameter_map.end();
+ ++it) {
+ options.linear_solver_ordering->AddElementToGroup(it->first, 0);
+ }
+ }
+
+ original_program->SetParameterBlockStatePtrsToUserStatePtrs();
+
+ // If the user requests gradient checking, construct a new
+ // ProblemImpl by wrapping the CostFunctions of problem_impl inside
+ // GradientCheckingCostFunction and replacing problem_impl with
+ // gradient_checking_problem_impl.
+ scoped_ptr<ProblemImpl> gradient_checking_problem_impl;
+ if (options.check_gradients) {
+ VLOG(1) << "Checking Gradients";
+ gradient_checking_problem_impl.reset(
+ CreateGradientCheckingProblemImpl(
+ problem_impl,
+ options.numeric_derivative_relative_step_size,
+ options.gradient_check_relative_precision));
+
+ // From here on, problem_impl will point to the gradient checking
+ // version.
+ problem_impl = gradient_checking_problem_impl.get();
+ }
+
+ // Create the three objects needed to minimize: the transformed program, the
+ // evaluator, and the linear solver.
+ scoped_ptr<Program> reduced_program(CreateReducedProgram(&options,
+ problem_impl,
+ &summary->fixed_cost,
+ &summary->error));
+ if (reduced_program == NULL) {
+ return;
+ }
+
+ summary->num_parameter_blocks_reduced = reduced_program->NumParameterBlocks();
+ summary->num_parameters_reduced = reduced_program->NumParameters();
+ summary->num_residual_blocks_reduced = reduced_program->NumResidualBlocks();
+ summary->num_residuals_reduced = reduced_program->NumResiduals();
+
+ if (summary->num_parameter_blocks_reduced == 0) {
+ summary->preprocessor_time_in_seconds =
+ WallTimeInSeconds() - solver_start_time;
+
+ LOG(INFO) << "Terminating: FUNCTION_TOLERANCE reached. "
+ << "No non-constant parameter blocks found.";
+
+ // FUNCTION_TOLERANCE is the right convergence here, as we know
+ // that the objective function is constant and cannot be changed
+ // any further.
+ summary->termination_type = FUNCTION_TOLERANCE;
+
+ const double post_process_start_time = WallTimeInSeconds();
+
+ SetSummaryFinalCost(summary);
+
+ // Ensure the program state is set to the user parameters on the way out.
+ original_program->SetParameterBlockStatePtrsToUserStatePtrs();
+ summary->postprocessor_time_in_seconds =
+ WallTimeInSeconds() - post_process_start_time;
+ return;
+ }
+
+ scoped_ptr<Evaluator> evaluator(CreateEvaluator(options,
+ problem_impl->parameter_map(),
+ reduced_program.get(),
+ &summary->error));
if (evaluator == NULL) {
return;
}
@@ -318,17 +752,18 @@ void SolverImpl::Solve(const Solver::Options& original_options,
// Collect the discontiguous parameters into a contiguous state vector.
reduced_program->ParameterBlocksToStateVector(parameters.data());
- time_t minimizer_start_time = time(NULL);
+ Vector original_parameters = parameters;
+
+ const double minimizer_start_time = WallTimeInSeconds();
summary->preprocessor_time_in_seconds =
minimizer_start_time - solver_start_time;
// Run the optimization.
- Minimize(options,
- reduced_program.get(),
- evaluator.get(),
- linear_solver.get(),
- parameters.data(),
- summary);
+ LineSearchMinimize(options,
+ reduced_program.get(),
+ evaluator.get(),
+ parameters.data(),
+ summary);
// If the user aborted mid-optimization or the optimization
// terminated because of a numerical failure, then return without
@@ -338,35 +773,100 @@ void SolverImpl::Solve(const Solver::Options& original_options,
return;
}
- time_t post_process_start_time = time(NULL);
+ const double post_process_start_time = WallTimeInSeconds();
// Push the contiguous optimized parameters back to the user's parameters.
reduced_program->StateVectorToParameterBlocks(parameters.data());
reduced_program->CopyParameterBlockStateToUserState();
- // Evaluate the final cost, residual vector and the jacobian
- // matrix if requested by the user.
- Evaluator::Evaluate(
- original_program,
- options.num_threads,
- &summary->final_cost,
- options.return_final_residuals ? &summary->final_residuals : NULL,
- options.return_final_gradient ? &summary->final_gradient : NULL,
- options.return_final_jacobian ? &summary->final_jacobian : NULL);
+ SetSummaryFinalCost(summary);
// Ensure the program state is set to the user parameters on the way out.
original_program->SetParameterBlockStatePtrsToUserStatePtrs();
+
+ const map<string, double>& evaluator_time_statistics =
+ 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);
+
// Stick a fork in it, we're done.
- summary->postprocessor_time_in_seconds = time(NULL) - post_process_start_time;
+ summary->postprocessor_time_in_seconds =
+ WallTimeInSeconds() - post_process_start_time;
+}
+
+
+bool SolverImpl::IsOrderingValid(const Solver::Options& options,
+ const ProblemImpl* problem_impl,
+ string* error) {
+ if (options.linear_solver_ordering->NumElements() !=
+ problem_impl->NumParameterBlocks()) {
+ *error = "Number of parameter blocks in user supplied ordering "
+ "does not match the number of parameter blocks in the problem";
+ return false;
+ }
+
+ const Program& program = problem_impl->program();
+ const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
+ for (vector<ParameterBlock*>::const_iterator it = parameter_blocks.begin();
+ it != parameter_blocks.end();
+ ++it) {
+ if (!options.linear_solver_ordering
+ ->IsMember(const_cast<double*>((*it)->user_state()))) {
+ *error = "Problem contains a parameter block that is not in "
+ "the user specified ordering.";
+ return false;
+ }
+ }
+
+ if (IsSchurType(options.linear_solver_type) &&
+ options.linear_solver_ordering->NumGroups() > 1) {
+ const vector<ResidualBlock*>& residual_blocks = program.residual_blocks();
+ const set<double*>& e_blocks =
+ options.linear_solver_ordering->group_to_elements().begin()->second;
+ if (!IsParameterBlockSetIndependent(e_blocks, residual_blocks)) {
+ *error = "The user requested the use of a Schur type solver. "
+ "But the first elimination group in the ordering is not an "
+ "independent set.";
+ return false;
+ }
+ }
+ return true;
+}
+
+bool SolverImpl::IsParameterBlockSetIndependent(
+ const set<double*>& parameter_block_ptrs,
+ const vector<ResidualBlock*>& residual_blocks) {
+ // 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 += parameter_block_ptrs.count(
+ parameter_blocks[i]->mutable_user_state());
+ }
+ if (count > 1) {
+ return false;
+ }
+ }
+ return true;
}
+
// Strips varying parameters and residuals, maintaining order, and updating
// num_eliminate_blocks.
bool SolverImpl::RemoveFixedBlocksFromProgram(Program* program,
- int* num_eliminate_blocks,
+ ParameterBlockOrdering* ordering,
double* fixed_cost,
string* error) {
- int original_num_eliminate_blocks = *num_eliminate_blocks;
vector<ParameterBlock*>* parameter_blocks =
program->mutable_parameter_blocks();
@@ -423,7 +923,7 @@ bool SolverImpl::RemoveFixedBlocksFromProgram(Program* program,
}
// Filter out unused or fixed parameter blocks, and update
- // num_eliminate_blocks as necessary.
+ // the ordering.
{
vector<ParameterBlock*>* parameter_blocks =
program->mutable_parameter_blocks();
@@ -432,8 +932,8 @@ bool SolverImpl::RemoveFixedBlocksFromProgram(Program* program,
ParameterBlock* parameter_block = (*parameter_blocks)[i];
if (parameter_block->index() == 1) {
(*parameter_blocks)[j++] = parameter_block;
- } else if (i < original_num_eliminate_blocks) {
- (*num_eliminate_blocks)--;
+ } else {
+ ordering->Remove(parameter_block->mutable_user_state());
}
}
parameter_blocks->resize(j);
@@ -451,70 +951,127 @@ Program* SolverImpl::CreateReducedProgram(Solver::Options* options,
ProblemImpl* problem_impl,
double* fixed_cost,
string* error) {
+ EventLogger event_logger("CreateReducedProgram");
+
+ CHECK_NOTNULL(options->linear_solver_ordering);
Program* original_program = problem_impl->mutable_program();
scoped_ptr<Program> transformed_program(new Program(*original_program));
+ event_logger.AddEvent("TransformedProgram");
- if (options->ordering_type == USER &&
- !ApplyUserOrdering(*problem_impl,
- options->ordering,
- transformed_program.get(),
- error)) {
- return NULL;
- }
-
- if (options->ordering_type == SCHUR && options->num_eliminate_blocks != 0) {
- *error = "Can't specify SCHUR ordering and num_eliminate_blocks "
- "at the same time; SCHUR ordering determines "
- "num_eliminate_blocks automatically.";
- return NULL;
- }
-
- if (options->ordering_type == SCHUR && options->ordering.size() != 0) {
- *error = "Can't specify SCHUR ordering type and the ordering "
- "vector at the same time; SCHUR ordering determines "
- "a suitable parameter ordering automatically.";
- return NULL;
- }
+ ParameterBlockOrdering* linear_solver_ordering =
+ options->linear_solver_ordering;
- int num_eliminate_blocks = options->num_eliminate_blocks;
+ const int min_group_id =
+ linear_solver_ordering->group_to_elements().begin()->first;
+ const int original_num_groups = linear_solver_ordering->NumGroups();
if (!RemoveFixedBlocksFromProgram(transformed_program.get(),
- &num_eliminate_blocks,
+ linear_solver_ordering,
fixed_cost,
error)) {
return NULL;
}
+ event_logger.AddEvent("RemoveFixedBlocks");
+
if (transformed_program->NumParameterBlocks() == 0) {
+ if (transformed_program->NumResidualBlocks() > 0) {
+ *error = "Zero parameter blocks but non-zero residual blocks"
+ " in the reduced program. Congratulations, you found a "
+ "Ceres bug! Please report this error to the developers.";
+ return NULL;
+ }
+
LOG(WARNING) << "No varying parameter blocks to optimize; "
<< "bailing early.";
return transformed_program.release();
}
- if (options->ordering_type == SCHUR) {
+ // If the user supplied an linear_solver_ordering with just one
+ // group, it is equivalent to the user supplying NULL as
+ // 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.
+ if (original_num_groups == 1 && IsSchurType(options->linear_solver_type)) {
vector<ParameterBlock*> schur_ordering;
- num_eliminate_blocks = ComputeSchurOrdering(*transformed_program,
- &schur_ordering);
+ const int num_eliminate_blocks = ComputeSchurOrdering(*transformed_program,
+ &schur_ordering);
CHECK_EQ(schur_ordering.size(), transformed_program->NumParameterBlocks())
<< "Congratulations, you found a Ceres bug! Please report this error "
<< "to the developers.";
- // Replace the transformed program's ordering with the schur ordering.
- swap(*transformed_program->mutable_parameter_blocks(), schur_ordering);
+ for (int i = 0; i < schur_ordering.size(); ++i) {
+ linear_solver_ordering->AddElementToGroup(
+ schur_ordering[i]->mutable_user_state(),
+ (i < num_eliminate_blocks) ? 0 : 1);
+ }
}
- options->num_eliminate_blocks = num_eliminate_blocks;
- CHECK_GE(options->num_eliminate_blocks, 0)
- << "Congratulations, you found a Ceres bug! Please report this error "
- << "to the developers.";
+ event_logger.AddEvent("SchurOrdering");
+
+ if (!ApplyUserOrdering(problem_impl->parameter_map(),
+ linear_solver_ordering,
+ transformed_program.get(),
+ error)) {
+ return NULL;
+ }
+ event_logger.AddEvent("ApplyOrdering");
+
+ // If the user requested the use of a Schur type solver, and
+ // supplied a non-NULL linear_solver_ordering object with more than
+ // one elimination group, then it can happen that after all the
+ // parameter blocks which are fixed or unused have been removed from
+ // the program and the ordering, there are no more parameter blocks
+ // in the first elimination group.
+ //
+ // In such a case, the use of a Schur type solver is not possible,
+ // as they assume there is at least one e_block. Thus, we
+ // automatically switch to one of the other solvers, depending on
+ // the user's indicated preferences.
+ if (IsSchurType(options->linear_solver_type) &&
+ original_num_groups > 1 &&
+ linear_solver_ordering->GroupSize(min_group_id) == 0) {
+ string msg = "No e_blocks remaining. Switching from ";
+ if (options->linear_solver_type == SPARSE_SCHUR) {
+ options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+ msg += "SPARSE_SCHUR to SPARSE_NORMAL_CHOLESKY.";
+ } else if (options->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.
+ options->linear_solver_type = DENSE_QR;
+ msg += "DENSE_SCHUR to DENSE_QR.";
+ } else if (options->linear_solver_type == ITERATIVE_SCHUR) {
+ msg += StringPrintf("ITERATIVE_SCHUR with %s preconditioner "
+ "to CGNR with JACOBI preconditioner.",
+ PreconditionerTypeToString(
+ options->preconditioner_type));
+ options->linear_solver_type = CGNR;
+ if (options->preconditioner_type != IDENTITY) {
+ // CGNR currently only supports the JACOBI preconditioner.
+ options->preconditioner_type = JACOBI;
+ }
+ }
- // Since the transformed program is the "active" program, and it is mutated,
- // update the parameter offsets and indices.
+ LOG(WARNING) << msg;
+ }
+
+ event_logger.AddEvent("AlternateSolver");
+
+ // Since the transformed program is the "active" program, and it is
+ // mutated, update the parameter offsets and indices.
transformed_program->SetParameterOffsetsAndIndex();
+
+ event_logger.AddEvent("SetOffsets");
return transformed_program.release();
}
LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options,
string* error) {
+ CHECK_NOTNULL(options);
+ CHECK_NOTNULL(options->linear_solver_ordering);
+ CHECK_NOTNULL(error);
+
if (options->trust_region_strategy_type == DOGLEG) {
if (options->linear_solver_type == ITERATIVE_SCHUR ||
options->linear_solver_type == CGNR) {
@@ -532,6 +1089,18 @@ LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options,
"SuiteSparse was not enabled when Ceres was built.";
return NULL;
}
+
+ if (options->preconditioner_type == CLUSTER_JACOBI) {
+ *error = "CLUSTER_JACOBI preconditioner not suppored. Please build Ceres "
+ "with SuiteSparse support.";
+ return NULL;
+ }
+
+ if (options->preconditioner_type == CLUSTER_TRIDIAGONAL) {
+ *error = "CLUSTER_TRIDIAGONAL preconditioner not suppored. Please build "
+ "Ceres with SuiteSparse support.";
+ return NULL;
+ }
#endif
#ifdef CERES_NO_CXSPARSE
@@ -543,6 +1112,13 @@ LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options,
}
#endif
+#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE)
+ if (options->linear_solver_type == SPARSE_SCHUR) {
+ *error = "Can't use SPARSE_SCHUR because neither SuiteSparse nor"
+ "CXSparse was enabled when Ceres was compiled.";
+ return NULL;
+ }
+#endif
if (options->linear_solver_max_num_iterations <= 0) {
*error = "Solver::Options::linear_solver_max_num_iterations is 0.";
@@ -568,52 +1144,8 @@ LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options,
linear_solver_options.preconditioner_type = options->preconditioner_type;
linear_solver_options.sparse_linear_algebra_library =
options->sparse_linear_algebra_library;
- linear_solver_options.use_block_amd = options->use_block_amd;
-
-#ifdef CERES_NO_SUITESPARSE
- if (linear_solver_options.preconditioner_type == SCHUR_JACOBI) {
- *error = "SCHUR_JACOBI preconditioner not suppored. Please build Ceres "
- "with SuiteSparse support.";
- return NULL;
- }
-
- if (linear_solver_options.preconditioner_type == CLUSTER_JACOBI) {
- *error = "CLUSTER_JACOBI preconditioner not suppored. Please build Ceres "
- "with SuiteSparse support.";
- return NULL;
- }
-
- if (linear_solver_options.preconditioner_type == CLUSTER_TRIDIAGONAL) {
- *error = "CLUSTER_TRIDIAGONAL preconditioner not suppored. Please build "
- "Ceres with SuiteSparse support.";
- return NULL;
- }
-#endif
linear_solver_options.num_threads = options->num_linear_solver_threads;
- linear_solver_options.num_eliminate_blocks =
- options->num_eliminate_blocks;
-
- if ((linear_solver_options.num_eliminate_blocks == 0) &&
- IsSchurType(linear_solver_options.type)) {
-#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE)
- LOG(INFO) << "No elimination block remaining switching to DENSE_QR.";
- linear_solver_options.type = DENSE_QR;
-#else
- LOG(INFO) << "No elimination block remaining "
- << "switching to SPARSE_NORMAL_CHOLESKY.";
- linear_solver_options.type = SPARSE_NORMAL_CHOLESKY;
-#endif
- }
-
-#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE)
- if (linear_solver_options.type == SPARSE_SCHUR) {
- *error = "Can't use SPARSE_SCHUR because neither SuiteSparse nor"
- "CXSparse was enabled when Ceres was compiled.";
- return NULL;
- }
-#endif
-
// The matrix used for storing the dense Schur complement has a
// single lock guarding the whole matrix. Running the
// SchurComplementSolver with multiple threads leads to maximum
@@ -628,56 +1160,67 @@ LinearSolver* SolverImpl::CreateLinearSolver(Solver::Options* options,
<< "switching to single-threaded.";
linear_solver_options.num_threads = 1;
}
-
- options->linear_solver_type = linear_solver_options.type;
options->num_linear_solver_threads = linear_solver_options.num_threads;
+ linear_solver_options.use_block_amd = options->use_block_amd;
+ const map<int, set<double*> >& groups =
+ options->linear_solver_ordering->group_to_elements();
+ for (map<int, set<double*> >::const_iterator it = groups.begin();
+ it != groups.end();
+ ++it) {
+ linear_solver_options.elimination_groups.push_back(it->second.size());
+ }
+ // Schur type solvers, expect at least two elimination groups. If
+ // there is only one elimination group, then CreateReducedProgram
+ // guarantees that this group only contains e_blocks. Thus we add a
+ // dummy elimination group with zero blocks in it.
+ if (IsSchurType(linear_solver_options.type) &&
+ linear_solver_options.elimination_groups.size() == 1) {
+ linear_solver_options.elimination_groups.push_back(0);
+ }
+
return LinearSolver::Create(linear_solver_options);
}
-bool SolverImpl::ApplyUserOrdering(const ProblemImpl& problem_impl,
- vector<double*>& ordering,
- Program* program,
- string* error) {
- if (ordering.size() != program->NumParameterBlocks()) {
+bool SolverImpl::ApplyUserOrdering(
+ const ProblemImpl::ParameterMap& parameter_map,
+ const ParameterBlockOrdering* ordering,
+ Program* program,
+ string* error) {
+ if (ordering->NumElements() != program->NumParameterBlocks()) {
*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 %ld blocks.",
+ "has %d blocks while the ordering has %d blocks.",
program->NumParameterBlocks(),
- ordering.size());
+ ordering->NumElements());
return false;
}
- // Ensure that there are no duplicates in the user's ordering.
- {
- vector<double*> ordering_copy(ordering);
- sort(ordering_copy.begin(), ordering_copy.end());
- if (unique(ordering_copy.begin(), ordering_copy.end())
- != ordering_copy.end()) {
- *error = "User specified ordering contains duplicates.";
- return false;
- }
- }
-
vector<ParameterBlock*>* parameter_blocks =
program->mutable_parameter_blocks();
-
- fill(parameter_blocks->begin(),
- parameter_blocks->end(),
- static_cast<ParameterBlock*>(NULL));
-
- const ProblemImpl::ParameterMap& parameter_map = problem_impl.parameter_map();
- for (int i = 0; i < ordering.size(); ++i) {
- ProblemImpl::ParameterMap::const_iterator it =
- parameter_map.find(ordering[i]);
- if (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 at position %d "
- " in options.ordering.", i);
- return false;
+ 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);
}
- (*parameter_blocks)[i] = it->second;
}
return true;
}
@@ -704,36 +1247,31 @@ static int MinParameterBlock(const ResidualBlock* residual_block,
// 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 SolverImpl::MaybeReorderResidualBlocks(const Solver::Options& options,
- Program* program,
- string* error) {
- // Only Schur types require the lexicographic reordering.
- if (!IsSchurType(options.linear_solver_type)) {
- return true;
- }
-
- CHECK_NE(0, options.num_eliminate_blocks)
- << "Congratulations, you found a Ceres bug! Please report this error "
- << "to the developers.";
+bool SolverImpl::LexicographicallyOrderResidualBlocks(
+ const int num_eliminate_blocks,
+ Program* program,
+ string* error) {
+ CHECK_GE(num_eliminate_blocks, 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(options.num_eliminate_blocks + 1);
+ vector<int> residual_blocks_per_e_block(num_eliminate_blocks + 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,
- options.num_eliminate_blocks);
+ int position = MinParameterBlock(residual_block, num_eliminate_blocks);
min_position_per_residual[i] = position;
- DCHECK_LE(position, options.num_eliminate_blocks);
+ DCHECK_LE(position, num_eliminate_blocks);
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(options.num_eliminate_blocks + 1);
+ vector<int> offsets(num_eliminate_blocks + 1);
std::partial_sum(residual_blocks_per_e_block.begin(),
residual_blocks_per_e_block.end(),
offsets.begin());
@@ -772,7 +1310,7 @@ bool SolverImpl::MaybeReorderResidualBlocks(const Solver::Options& options,
// Sanity check #1: The difference in bucket offsets should match the
// histogram sizes.
- for (int i = 0; i < options.num_eliminate_blocks; ++i) {
+ for (int i = 0; i < num_eliminate_blocks; ++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.";
@@ -789,15 +1327,76 @@ bool SolverImpl::MaybeReorderResidualBlocks(const Solver::Options& options,
return true;
}
-Evaluator* SolverImpl::CreateEvaluator(const Solver::Options& options,
- Program* program,
- string* error) {
+Evaluator* SolverImpl::CreateEvaluator(
+ const Solver::Options& options,
+ const ProblemImpl::ParameterMap& parameter_map,
+ Program* program,
+ string* error) {
Evaluator::Options evaluator_options;
evaluator_options.linear_solver_type = options.linear_solver_type;
- evaluator_options.num_eliminate_blocks = options.num_eliminate_blocks;
+ evaluator_options.num_eliminate_blocks =
+ (options.linear_solver_ordering->NumGroups() > 0 &&
+ IsSchurType(options.linear_solver_type))
+ ? (options.linear_solver_ordering
+ ->group_to_elements().begin()
+ ->second.size())
+ : 0;
evaluator_options.num_threads = options.num_threads;
return Evaluator::Create(evaluator_options, program, error);
}
+CoordinateDescentMinimizer* SolverImpl::CreateInnerIterationMinimizer(
+ const Solver::Options& options,
+ const Program& program,
+ const ProblemImpl::ParameterMap& parameter_map,
+ Solver::Summary* summary) {
+ scoped_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer(
+ new CoordinateDescentMinimizer);
+ scoped_ptr<ParameterBlockOrdering> inner_iteration_ordering;
+ ParameterBlockOrdering* ordering_ptr = NULL;
+
+ if (options.inner_iteration_ordering == NULL) {
+ // 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.
+ inner_iteration_ordering.reset(new ParameterBlockOrdering);
+ ComputeRecursiveIndependentSetOrdering(program,
+ inner_iteration_ordering.get());
+ inner_iteration_ordering->Reverse();
+ ordering_ptr = inner_iteration_ordering.get();
+ } else {
+ const map<int, set<double*> >& group_to_elements =
+ options.inner_iteration_ordering->group_to_elements();
+
+ // Iterate over each group and verify that it is an independent
+ // set.
+ map<int, set<double*> >::const_iterator it = group_to_elements.begin();
+ for ( ; it != group_to_elements.end(); ++it) {
+ if (!IsParameterBlockSetIndependent(it->second,
+ program.residual_blocks())) {
+ summary->error =
+ StringPrintf("The user-provided "
+ "parameter_blocks_for_inner_iterations does not "
+ "form an independent set. Group Id: %d", it->first);
+ return NULL;
+ }
+ }
+ ordering_ptr = options.inner_iteration_ordering;
+ }
+
+ if (!inner_iteration_minimizer->Init(program,
+ parameter_map,
+ *ordering_ptr,
+ &summary->error)) {
+ return NULL;
+ }
+
+ summary->inner_iterations = true;
+ SummarizeOrdering(ordering_ptr, &(summary->inner_iteration_ordering_used));
+
+ return inner_iteration_minimizer.release();
+}
+
} // namespace internal
} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/solver_impl.h b/extern/libmv/third_party/ceres/internal/ceres/solver_impl.h
index 11b44de6f42..c5f5efad3d7 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/solver_impl.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/solver_impl.h
@@ -31,17 +31,20 @@
#ifndef CERES_INTERNAL_SOLVER_IMPL_H_
#define CERES_INTERNAL_SOLVER_IMPL_H_
+#include <set>
#include <string>
#include <vector>
#include "ceres/internal/port.h"
+#include "ceres/ordered_groups.h"
+#include "ceres/problem_impl.h"
#include "ceres/solver.h"
namespace ceres {
namespace internal {
+class CoordinateDescentMinimizer;
class Evaluator;
class LinearSolver;
-class ProblemImpl;
class Program;
class SolverImpl {
@@ -52,10 +55,19 @@ class SolverImpl {
ProblemImpl* problem_impl,
Solver::Summary* summary);
+ static void TrustRegionSolve(const Solver::Options& options,
+ ProblemImpl* problem_impl,
+ Solver::Summary* summary);
+
+ static void LineSearchSolve(const Solver::Options& options,
+ ProblemImpl* problem_impl,
+ Solver::Summary* summary);
+
// Create the transformed Program, which has all the fixed blocks
// and residuals eliminated, and in the case of automatic schur
// ordering, has the E blocks first in the resulting program, with
// options.num_eliminate_blocks set appropriately.
+ //
// If fixed_cost is not NULL, the residual blocks that are removed
// are evaluated and the sum of their cost is returned in fixed_cost.
static Program* CreateReducedProgram(Solver::Options* options,
@@ -71,46 +83,73 @@ class SolverImpl {
static LinearSolver* CreateLinearSolver(Solver::Options* options,
string* error);
- // Reorder the parameter blocks in program using the vector
- // ordering. A return value of true indicates success and false
- // indicates an error was encountered whose cause is logged to
- // LOG(ERROR).
- static bool ApplyUserOrdering(const ProblemImpl& problem_impl,
- vector<double*>& ordering,
+ // Reorder the parameter blocks in program using the ordering. A
+ // return value of true indicates success and false indicates an
+ // error was encountered whose cause is logged to LOG(ERROR).
+ static bool ApplyUserOrdering(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.
- static bool MaybeReorderResidualBlocks(const Solver::Options& options,
- Program* program,
- string* error);
+ // residuals involving e block (i.e., the first num_eliminate_block
+ // parameter blocks) occur together. This is a necessary condition
+ // for the Schur eliminator.
+ static bool LexicographicallyOrderResidualBlocks(
+ const int num_eliminate_blocks,
+ Program* program,
+ string* error);
// Create the appropriate evaluator for the transformed program.
- static Evaluator* CreateEvaluator(const Solver::Options& options,
- Program* program,
- string* error);
-
- // Run the minimization for the given evaluator and configuration.
- static void Minimize(const Solver::Options &options,
- Program* program,
- Evaluator* evaluator,
- LinearSolver* linear_solver,
- double* parameters,
- Solver::Summary* summary);
+ static Evaluator* CreateEvaluator(
+ const Solver::Options& options,
+ const ProblemImpl::ParameterMap& parameter_map,
+ Program* program,
+ string* error);
+
+ // Run the TrustRegionMinimizer for the given evaluator and configuration.
+ static void TrustRegionMinimize(
+ const Solver::Options &options,
+ Program* program,
+ CoordinateDescentMinimizer* inner_iteration_minimizer,
+ Evaluator* evaluator,
+ LinearSolver* linear_solver,
+ double* parameters,
+ Solver::Summary* summary);
+
+ // Run the LineSearchMinimizer for the given evaluator and configuration.
+ static void LineSearchMinimize(
+ const Solver::Options &options,
+ Program* program,
+ Evaluator* evaluator,
+ double* parameters,
+ Solver::Summary* summary);
// Remove the fixed or unused parameter blocks and residuals
// depending only on fixed parameters from the problem. Also updates
// num_eliminate_blocks, since removed parameters changes the point
- // at which the eliminated blocks is valid.
- // If fixed_cost is not NULL, the residual blocks that are removed
- // are evaluated and the sum of their cost is returned in fixed_cost.
+ // at which the eliminated blocks is valid. If fixed_cost is not
+ // NULL, the residual blocks that are removed are evaluated and the
+ // sum of their cost is returned in fixed_cost.
static bool RemoveFixedBlocksFromProgram(Program* program,
- int* num_eliminate_blocks,
+ ParameterBlockOrdering* ordering,
double* fixed_cost,
string* error);
+
+ static bool IsOrderingValid(const Solver::Options& options,
+ const ProblemImpl* problem_impl,
+ string* error);
+
+ static bool IsParameterBlockSetIndependent(
+ const set<double*>& parameter_block_ptrs,
+ const vector<ResidualBlock*>& residual_blocks);
+
+ static CoordinateDescentMinimizer* CreateInnerIterationMinimizer(
+ const Solver::Options& options,
+ const Program& program,
+ const ProblemImpl::ParameterMap& parameter_map,
+ Solver::Summary* summary);
};
} // namespace internal
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
index 9e00b4402dc..dd05f0c6f41 100644
--- 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
@@ -39,12 +39,13 @@
#endif
#include "ceres/compressed_row_sparse_matrix.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/internal/eigen.h"
-#include "ceres/internal/scoped_ptr.h"
#include "ceres/types.h"
+#include "ceres/wall_time.h"
namespace ceres {
namespace internal {
@@ -103,6 +104,8 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingCXSparse(
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double * x) {
+ EventLogger event_logger("SparseNormalCholeskySolver::CXSparse::Solve");
+
LinearSolver::Summary summary;
summary.num_iterations = 1;
const int num_cols = A->num_cols();
@@ -129,25 +132,34 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingCXSparse(
// off of Jt to compute the Cholesky factorization of the normal
// equations.
cs_di* A2 = cs_transpose(&At, 1);
- cs_di* AtA = cs_multiply(&At,A2);
+ cs_di* AtA = cs_multiply(&At, A2);
cxsparse_.Free(A2);
if (per_solve_options.D != NULL) {
A->DeleteRows(num_cols);
}
+ event_logger.AddEvent("Setup");
+
// Compute symbolic factorization if not available.
if (cxsparse_factor_ == NULL) {
cxsparse_factor_ = CHECK_NOTNULL(cxsparse_.AnalyzeCholesky(AtA));
}
+ event_logger.AddEvent("Analysis");
+
+
// Solve the linear system.
if (cxsparse_.SolveCholesky(AtA, cxsparse_factor_, Atb.data())) {
VectorRef(x, Atb.rows()) = Atb;
summary.termination_type = TOLERANCE;
}
+ event_logger.AddEvent("Solve");
+
cxsparse_.Free(AtA);
+
+ event_logger.AddEvent("Teardown");
return summary;
}
#else
@@ -169,9 +181,9 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse(
const double* b,
const LinearSolver::PerSolveOptions& per_solve_options,
double * x) {
- const time_t start_time = time(NULL);
- const int num_cols = A->num_cols();
+ EventLogger event_logger("SparseNormalCholeskySolver::SuiteSparse::Solve");
+ const int num_cols = A->num_cols();
LinearSolver::Summary summary;
Vector Atb = Vector::Zero(num_cols);
A->LeftMultiply(b, Atb.data());
@@ -189,7 +201,7 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse(
CHECK_NOTNULL(lhs.get());
cholmod_dense* rhs = ss_.CreateDenseVector(Atb.data(), num_cols, num_cols);
- const time_t init_time = time(NULL);
+ event_logger.AddEvent("Setup");
if (factor_ == NULL) {
if (options_.use_block_amd) {
@@ -206,11 +218,10 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse(
}
CHECK_NOTNULL(factor_);
-
- const time_t symbolic_time = time(NULL);
+ event_logger.AddEvent("Analysis");
cholmod_dense* sol = ss_.SolveCholesky(lhs.get(), factor_, rhs);
- const time_t solve_time = time(NULL);
+ event_logger.AddEvent("Solve");
ss_.Free(rhs);
rhs = NULL;
@@ -228,12 +239,7 @@ LinearSolver::Summary SparseNormalCholeskySolver::SolveImplUsingSuiteSparse(
summary.termination_type = TOLERANCE;
}
- const time_t cleanup_time = time(NULL);
- VLOG(2) << "time (sec) total: " << (cleanup_time - start_time)
- << " init: " << (init_time - start_time)
- << " symbolic: " << (symbolic_time - init_time)
- << " solve: " << (solve_time - symbolic_time)
- << " cleanup: " << (cleanup_time - solve_time);
+ event_logger.AddEvent("Teardown");
return summary;
}
#else
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
index 40d9e0a0327..8d48096d4c6 100644
--- 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
@@ -35,8 +35,8 @@
#define CERES_INTERNAL_SPARSE_NORMAL_CHOLESKY_SOLVER_H_
#include "ceres/cxsparse.h"
-#include "ceres/linear_solver.h"
#include "ceres/internal/macros.h"
+#include "ceres/linear_solver.h"
#include "ceres/suitesparse.h"
namespace ceres {
diff --git a/extern/libmv/third_party/ceres/internal/ceres/split.cc b/extern/libmv/third_party/ceres/internal/ceres/split.cc
index c65c8a5bb5d..3edbc281340 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/split.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/split.cc
@@ -28,10 +28,11 @@
//
// Author: keir@google.com (Keir Mierle)
+#include "ceres/split.h"
+
#include <string>
#include <vector>
#include <iterator>
-#include "ceres/split.h"
#include "ceres/internal/port.h"
namespace ceres {
diff --git a/extern/libmv/third_party/ceres/internal/ceres/split.h b/extern/libmv/third_party/ceres/internal/ceres/split.h
index ec579e974da..4df48c3a7cd 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/split.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/split.h
@@ -2,7 +2,7 @@
// Author: keir@google.com (Keir Mierle)
#ifndef CERES_INTERNAL_SPLIT_H_
-#define VISION_OPTIMIZATION_LEAST_SQUARES_INTERNAL_SPLIT_H_
+#define CERES_INTERNAL_SPLIT_H_
#include <string>
#include <vector>
diff --git a/extern/libmv/third_party/ceres/internal/ceres/stl_util.h b/extern/libmv/third_party/ceres/internal/ceres/stl_util.h
index a1a19e8b3ce..08f15ec8398 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/stl_util.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/stl_util.h
@@ -31,6 +31,8 @@
#ifndef CERES_INTERNAL_STL_UTIL_H_
#define CERES_INTERNAL_STL_UTIL_H_
+#include <algorithm>
+
namespace ceres {
// STLDeleteContainerPointers()
@@ -53,6 +55,20 @@ void STLDeleteContainerPointers(ForwardIterator begin,
}
}
+// 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(),
diff --git a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc
index 396a48b7d97..ce204674dce 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.cc
@@ -28,13 +28,14 @@
//
// 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/stringprintf.h"
#include "ceres/internal/port.h"
namespace ceres {
diff --git a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h
index f2f907ab32d..cd1be142aed 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/stringprintf.h
@@ -65,17 +65,17 @@ namespace internal {
// Return a C++ string.
extern string StringPrintf(const char* format, ...)
// Tell the compiler to do printf format string checking.
- CERES_PRINTF_ATTRIBUTE(1,2);
+ 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);
+ 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);
+ 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.
diff --git a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc
index cf3c48f84e6..d200aeb82f3 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.cc
@@ -135,10 +135,11 @@ cholmod_factor* SuiteSparse::BlockAnalyzeCholesky(
return AnalyzeCholeskyWithUserOrdering(A, ordering);
}
-cholmod_factor* SuiteSparse::AnalyzeCholeskyWithUserOrdering(cholmod_sparse* A,
- const vector<int>& ordering) {
+cholmod_factor* SuiteSparse::AnalyzeCholeskyWithUserOrdering(
+ cholmod_sparse* A,
+ const vector<int>& ordering) {
CHECK_EQ(ordering.size(), A->nrow);
- cc_.nmethods = 1 ;
+ cc_.nmethods = 1;
cc_.method[0].ordering = CHOLMOD_GIVEN;
cholmod_factor* factor =
cholmod_analyze_p(A, const_cast<int*>(&ordering[0]), NULL, 0, &cc_);
diff --git a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h
index eb691c0c0ed..3fe79080d5d 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/suitesparse.h
@@ -39,9 +39,9 @@
#include <string>
#include <vector>
-#include <glog/logging.h>
-#include "cholmod.h"
#include "ceres/internal/port.h"
+#include "cholmod.h"
+#include "glog/logging.h"
namespace ceres {
namespace internal {
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
index ed8677ea18a..a09f38ee24e 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc
@@ -71,7 +71,8 @@ TripletSparseMatrix::TripletSparseMatrix(int num_rows,
}
TripletSparseMatrix::TripletSparseMatrix(const TripletSparseMatrix& orig)
- : num_rows_(orig.num_rows_),
+ : SparseMatrix(),
+ num_rows_(orig.num_rows_),
num_cols_(orig.num_cols_),
max_num_nonzeros_(orig.max_num_nonzeros_),
num_nonzeros_(orig.num_nonzeros_),
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
index 76c4f8a7580..981c60a12e7 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.cc
@@ -45,8 +45,10 @@
#include "ceres/internal/scoped_ptr.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 {
@@ -56,28 +58,13 @@ namespace {
const double kEpsilon = 1e-12;
} // namespace
-// Execute the list of IterationCallbacks sequentially. If any one of
-// the callbacks does not return SOLVER_CONTINUE, then stop and return
-// its status.
-CallbackReturnType TrustRegionMinimizer::RunCallbacks(
- const IterationSummary& iteration_summary) {
- for (int i = 0; i < options_.callbacks.size(); ++i) {
- const CallbackReturnType status =
- (*options_.callbacks[i])(iteration_summary);
- if (status != SOLVER_CONTINUE) {
- return status;
- }
- }
- return SOLVER_CONTINUE;
-}
-
// 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 / (kEpsilon + sqrt(scale[i]));
+ scale[i] = 1.0 / (1.0 + sqrt(scale[i]));
}
}
@@ -96,29 +83,19 @@ bool TrustRegionMinimizer::MaybeDumpLinearLeastSquaresProblem(
// moved inside TrustRegionStrategy, its not clear how we dump the
// regularization vector/matrix anymore.
//
- // Doing this right requires either an API change to the
- // TrustRegionStrategy and/or how LinearLeastSquares problems are
- // stored on disk.
+ // Also num_eliminate_blocks is not visible to the trust region
+ // minimizer either.
//
- // For now, we will just not dump the regularizer.
- return (!binary_search(options_.lsqp_iterations_to_dump.begin(),
- options_.lsqp_iterations_to_dump.end(),
- iteration) ||
- DumpLinearLeastSquaresProblem(options_.lsqp_dump_directory,
- iteration,
- options_.lsqp_dump_format_type,
- jacobian,
- NULL,
- residuals,
- step,
- options_.num_eliminate_blocks));
+ // Both of these indicate that this is the wrong place for this
+ // code, and going forward this should needs fixing/refactoring.
+ return true;
}
void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
double* parameters,
Solver::Summary* summary) {
- time_t start_time = time(NULL);
- time_t iteration_start_time = start_time;
+ double start_time = WallTimeInSeconds();
+ double iteration_start_time = start_time;
Init(options);
summary->termination_type = NO_CONVERGENCE;
@@ -149,7 +126,6 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
iteration_summary.iteration = 0;
iteration_summary.step_is_valid = false;
iteration_summary.step_is_successful = false;
- iteration_summary.cost = summary->initial_cost;
iteration_summary.cost_change = 0.0;
iteration_summary.gradient_max_norm = 0.0;
iteration_summary.step_norm = 0.0;
@@ -169,6 +145,9 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
return;
}
+ summary->initial_cost = cost + summary->fixed_cost;
+ iteration_summary.cost = cost + summary->fixed_cost;
+
int num_consecutive_nonmonotonic_steps = 0;
double minimum_cost = cost;
double reference_cost = cost;
@@ -189,45 +168,34 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
// The initial gradient max_norm is bounded from below so that we do
// not divide by zero.
- const double gradient_max_norm_0 =
+ const double initial_gradient_max_norm =
max(iteration_summary.gradient_max_norm, kEpsilon);
const double absolute_gradient_tolerance =
- options_.gradient_tolerance * gradient_max_norm_0;
+ options_.gradient_tolerance * initial_gradient_max_norm;
if (iteration_summary.gradient_max_norm <= absolute_gradient_tolerance) {
summary->termination_type = GRADIENT_TOLERANCE;
VLOG(1) << "Terminating: Gradient tolerance reached."
<< "Relative gradient max norm: "
- << iteration_summary.gradient_max_norm / gradient_max_norm_0
+ << iteration_summary.gradient_max_norm / initial_gradient_max_norm
<< " <= " << options_.gradient_tolerance;
return;
}
iteration_summary.iteration_time_in_seconds =
- time(NULL) - iteration_start_time;
- iteration_summary.cumulative_time_in_seconds = time(NULL) - start_time +
- summary->preprocessor_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);
- // Call the various callbacks.
- switch (RunCallbacks(iteration_summary)) {
- case SOLVER_TERMINATE_SUCCESSFULLY:
- summary->termination_type = USER_SUCCESS;
- VLOG(1) << "Terminating: User callback returned USER_SUCCESS.";
- return;
- case SOLVER_ABORT:
- summary->termination_type = USER_ABORT;
- VLOG(1) << "Terminating: User callback returned USER_ABORT.";
- return;
- case SOLVER_CONTINUE:
- break;
- default:
- LOG(FATAL) << "Unknown type of user callback status";
- }
-
int num_consecutive_invalid_steps = 0;
while (true) {
- iteration_start_time = time(NULL);
+ if (!RunCallbacks(options.callbacks, iteration_summary, summary)) {
+ return;
+ }
+
+ iteration_start_time = WallTimeInSeconds();
if (iteration_summary.iteration >= options_.max_num_iterations) {
summary->termination_type = NO_CONVERGENCE;
VLOG(1) << "Terminating: Maximum number of iterations reached.";
@@ -248,7 +216,7 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
iteration_summary.step_is_valid = false;
iteration_summary.step_is_successful = false;
- const time_t strategy_start_time = time(NULL);
+ const double strategy_start_time = WallTimeInSeconds();
TrustRegionStrategy::PerSolveOptions per_solve_options;
per_solve_options.eta = options_.eta;
TrustRegionStrategy::Summary strategy_summary =
@@ -258,7 +226,7 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
trust_region_step.data());
iteration_summary.step_solver_time_in_seconds =
- time(NULL) - strategy_start_time;
+ WallTimeInSeconds() - strategy_start_time;
iteration_summary.linear_solver_iterations =
strategy_summary.num_iterations;
@@ -270,23 +238,24 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
<< options.lsqp_dump_directory << "but failed.";
}
- double new_model_cost = 0.0;
+ double model_cost_change = 0.0;
if (strategy_summary.termination_type != FAILURE) {
- // new_model_cost = 1/2 |f + J * step|^2
- model_residuals = residuals;
+ // 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());
- new_model_cost = model_residuals.squaredNorm() / 2.0;
-
- // In exact arithmetic, this would never be the case. But poorly
- // conditioned matrices can give rise to situations where the
- // new_model_cost can actually be larger than half the squared
- // norm of the residual vector. We allow for small tolerance
- // around cost and beyond that declare the step to be invalid.
- if ((1.0 - new_model_cost / cost) < -kEpsilon) {
+ model_cost_change = -(residuals.dot(model_residuals) +
+ model_residuals.squaredNorm() / 2.0);
+
+ if (model_cost_change < 0.0) {
VLOG(1) << "Invalid step: current_cost: " << cost
- << " new_model_cost " << new_model_cost
- << " absolute difference " << (cost - new_model_cost)
- << " relative difference " << (1.0 - new_model_cost/cost);
+ << " absolute difference " << model_cost_change
+ << " relative difference " << (model_cost_change / cost);
} else {
iteration_summary.step_is_valid = true;
}
@@ -299,10 +268,12 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
if (++num_consecutive_invalid_steps >=
options_.max_num_consecutive_invalid_steps) {
summary->termination_type = NUMERICAL_FAILURE;
- LOG(WARNING) << "Terminating. Number of successive invalid steps more "
- << "than "
- << "Solver::Options::max_num_consecutive_invalid_steps: "
- << options_.max_num_consecutive_invalid_steps;
+ summary->error = StringPrintf(
+ "Terminating. Number of successive invalid steps more "
+ "than Solver::Options::max_num_consecutive_invalid_steps: %d",
+ options_.max_num_consecutive_invalid_steps);
+
+ LOG(WARNING) << summary->error;
return;
}
@@ -311,7 +282,7 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
// 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;
+ iteration_summary.cost = cost + summary->fixed_cost;
iteration_summary.cost_change = 0.0;
iteration_summary.gradient_max_norm =
summary->iterations.back().gradient_max_norm;
@@ -322,51 +293,19 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
// The step is numerically valid, so now we can judge its quality.
num_consecutive_invalid_steps = 0;
- // We allow some slop around 0, and clamp the model_cost_change
- // at kEpsilon * min(1.0, cost) from below.
- //
- // In exact arithmetic this should never be needed, as we are
- // guaranteed to new_model_cost <= cost. However, due to various
- // numerical issues, it is possible that new_model_cost is
- // nearly equal to cost, and the difference is a small negative
- // number. To make sure that the relative_decrease computation
- // remains sane, as clamp the difference (cost - new_model_cost)
- // from below at a small positive number.
- //
- // This number is the minimum of kEpsilon * (cost, 1.0), which
- // ensures that it will never get too large in absolute value,
- // while scaling down proportionally with the magnitude of the
- // cost. This is important for problems where the minimum of the
- // objective function is near zero.
- const double model_cost_change =
- max(kEpsilon * min(1.0, cost), cost - new_model_cost);
-
// Undo the Jacobian column scaling.
delta = (trust_region_step.array() * scale.array()).matrix();
- iteration_summary.step_norm = 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) {
- VLOG(1) << "Terminating. Parameter tolerance reached. "
- << "relative step_norm: "
- << iteration_summary.step_norm /
- (x_norm + options_.parameter_tolerance)
- << " <= " << options_.parameter_tolerance;
- summary->termination_type = PARAMETER_TOLERANCE;
- return;
- }
-
if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) {
summary->termination_type = NUMERICAL_FAILURE;
- LOG(WARNING) << "Terminating. Failed to compute "
- << "Plus(x, delta, x_plus_delta).";
+ summary->error =
+ "Terminating. Failed to compute Plus(x, delta, x_plus_delta).";
+
+ LOG(WARNING) << summary->error;
return;
}
// Try this step.
- double new_cost;
+ double new_cost = numeric_limits<double>::max();
if (!evaluator->Evaluate(x_plus_delta.data(),
&new_cost,
NULL, NULL, NULL)) {
@@ -375,6 +314,45 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
LOG(WARNING) << "Step failed to evaluate. "
<< "Treating it as step with infinite cost";
new_cost = numeric_limits<double>::max();
+ } else {
+ // Check if performing an inner iteration will make it better.
+ if (options.inner_iteration_minimizer != NULL) {
+ 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(2) << "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(2) << "Inner iteration succeeded; current cost: " << cost
+ << " x_plus_delta_cost: " << x_plus_delta_cost
+ << " new_cost: " << new_cost;
+ }
+ }
+ }
+
+ 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) {
+ VLOG(1) << "Terminating. Parameter tolerance reached. "
+ << "relative step_norm: "
+ << iteration_summary.step_norm /
+ (x_norm + options_.parameter_tolerance)
+ << " <= " << options_.parameter_tolerance;
+ summary->termination_type = PARAMETER_TOLERANCE;
+ return;
}
VLOG(2) << "old cost: " << cost << " new cost: " << new_cost;
@@ -421,6 +399,7 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
accumulated_candidate_model_cost_change += model_cost_change;
accumulated_reference_model_cost_change += model_cost_change;
if (relative_decrease <= options_.min_relative_decrease) {
+ iteration_summary.step_is_nonmonotonic = true;
VLOG(2) << "Non-monotonic step! "
<< " relative_decrease: " << relative_decrease
<< " historical_relative_decrease: "
@@ -443,7 +422,9 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
NULL,
jacobian)) {
summary->termination_type = NUMERICAL_FAILURE;
- LOG(WARNING) << "Terminating: Residual and Jacobian evaluation failed.";
+ summary->error =
+ "Terminating: Residual and Jacobian evaluation failed.";
+ LOG(WARNING) << summary->error;
return;
}
@@ -455,7 +436,8 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
summary->termination_type = GRADIENT_TOLERANCE;
VLOG(1) << "Terminating: Gradient tolerance reached."
<< "Relative gradient max norm: "
- << iteration_summary.gradient_max_norm / gradient_max_norm_0
+ << (iteration_summary.gradient_max_norm /
+ initial_gradient_max_norm)
<< " <= " << options_.gradient_tolerance;
return;
}
@@ -523,25 +505,11 @@ void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
}
iteration_summary.iteration_time_in_seconds =
- time(NULL) - iteration_start_time;
- iteration_summary.cumulative_time_in_seconds = time(NULL) - start_time +
- summary->preprocessor_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);
-
- switch (RunCallbacks(iteration_summary)) {
- case SOLVER_TERMINATE_SUCCESSFULLY:
- summary->termination_type = USER_SUCCESS;
- VLOG(1) << "Terminating: User callback returned USER_SUCCESS.";
- return;
- case SOLVER_ABORT:
- summary->termination_type = USER_ABORT;
- VLOG(1) << "Terminating: User callback returned USER_ABORT.";
- return;
- case SOLVER_CONTINUE:
- break;
- default:
- LOG(FATAL) << "Unknown type of user callback status";
- }
}
}
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
index a4f5ba3674d..9a022843233 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/trust_region_minimizer.h
@@ -39,8 +39,7 @@ namespace ceres {
namespace internal {
// Generic trust region minimization algorithm. The heavy lifting is
-// done by a TrustRegionStrategy object passed in as one of the
-// arguments to the Minimize method.
+// done by a TrustRegionStrategy object passed in as part of options.
//
// For example usage, see SolverImpl::Minimize.
class TrustRegionMinimizer : public Minimizer {
@@ -53,11 +52,10 @@ class TrustRegionMinimizer : public Minimizer {
private:
void Init(const Minimizer::Options& options);
void EstimateScale(const SparseMatrix& jacobian, double* scale) const;
- CallbackReturnType RunCallbacks(const IterationSummary& iteration_summary);
- bool MaybeDumpLinearLeastSquaresProblem( const int iteration,
- const SparseMatrix* jacobian,
- const double* residuals,
- const double* step) const;
+ bool MaybeDumpLinearLeastSquaresProblem(const int iteration,
+ const SparseMatrix* jacobian,
+ const double* residuals,
+ const double* step) const;
Minimizer::Options options_;
};
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
index 89bc19d084b..c68269d0449 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.cc
@@ -1,3 +1,35 @@
+// 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"
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
index 391da97d5eb..f150594bbd2 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/trust_region_strategy.h
@@ -52,7 +52,7 @@ class SparseMatrix;
// radius to scale the damping term, which controls the step size, but
// does not set a hard limit on its size.
class TrustRegionStrategy {
-public:
+ public:
struct Options {
Options()
: trust_region_strategy_type(LEVENBERG_MARQUARDT),
diff --git a/extern/libmv/third_party/ceres/internal/ceres/types.cc b/extern/libmv/third_party/ceres/internal/ceres/types.cc
index 05e573ff6d5..2e19322cc76 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/types.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/types.cc
@@ -28,15 +28,23 @@
//
// 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;}
-const char* LinearSolverTypeToString(LinearSolverType solver_type) {
- switch (solver_type) {
+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);
@@ -49,9 +57,20 @@ const char* LinearSolverTypeToString(LinearSolverType solver_type) {
}
}
-const char* PreconditionerTypeToString(
- PreconditionerType preconditioner_type) {
- switch (preconditioner_type) {
+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);
@@ -62,9 +81,19 @@ const char* PreconditionerTypeToString(
}
}
+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 sparse_linear_algebra_library_type) {
- switch (sparse_linear_algebra_library_type) {
+ SparseLinearAlgebraLibraryType type) {
+ switch (type) {
CASESTR(SUITE_SPARSE);
CASESTR(CX_SPARSE);
default:
@@ -72,19 +101,121 @@ const char* SparseLinearAlgebraLibraryTypeToString(
}
}
-const char* OrderingTypeToString(OrderingType ordering_type) {
- switch (ordering_type) {
- CASESTR(NATURAL);
- CASESTR(USER);
- CASESTR(SCHUR);
+
+bool StringToSparseLinearAlgebraLibraryType(
+ string value,
+ SparseLinearAlgebraLibraryType* type) {
+ UpperCase(&value);
+ STRENUM(SUITE_SPARSE);
+ STRENUM(CX_SPARSE);
+ 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);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToLineSearchDirectionType(string value,
+ LineSearchDirectionType* type) {
+ UpperCase(&value);
+ STRENUM(STEEPEST_DESCENT);
+ STRENUM(NONLINEAR_CONJUGATE_GRADIENT);
+ STRENUM(LBFGS);
+ return false;
+}
+
+const char* LineSearchTypeToString(LineSearchType type) {
+ switch (type) {
+ CASESTR(ARMIJO);
default:
return "UNKNOWN";
}
}
-const char* SolverTerminationTypeToString(
- SolverTerminationType termination_type) {
- switch (termination_type) {
+bool StringToLineSearchType(string value, LineSearchType* type) {
+ UpperCase(&value);
+ STRENUM(ARMIJO);
+ return false;
+}
+
+const char* NonlinearConjugateGradientTypeToString(
+ NonlinearConjugateGradientType type) {
+ switch (type) {
+ CASESTR(FLETCHER_REEVES);
+ CASESTR(POLAK_RIBIRERE);
+ CASESTR(HESTENES_STIEFEL);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToNonlinearConjugateGradientType(
+ string value,
+ NonlinearConjugateGradientType* type) {
+ UpperCase(&value);
+ STRENUM(FLETCHER_REEVES);
+ STRENUM(POLAK_RIBIRERE);
+ STRENUM(HESTENES_STIEFEL);
+ return false;
+}
+
+const char* SolverTerminationTypeToString(SolverTerminationType type) {
+ switch (type) {
CASESTR(NO_CONVERGENCE);
CASESTR(FUNCTION_TOLERANCE);
CASESTR(GRADIENT_TOLERANCE);
@@ -98,29 +229,20 @@ const char* SolverTerminationTypeToString(
}
}
-#if 0 /* UNUSED */
-static const char* SparseLinearAlgebraTypeToString(
- SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type) {
- switch (sparse_linear_algebra_library_type) {
- CASESTR(CX_SPARSE);
- CASESTR(SUITE_SPARSE);
- default:
- return "UNKNOWN";
- }
-}
-#endif
-
-const char* TrustRegionStrategyTypeToString(
- TrustRegionStrategyType trust_region_strategy_type) {
- switch (trust_region_strategy_type) {
- CASESTR(LEVENBERG_MARQUARDT);
- CASESTR(DOGLEG);
+const char* LinearSolverTerminationTypeToString(
+ LinearSolverTerminationType type) {
+ switch (type) {
+ CASESTR(TOLERANCE);
+ CASESTR(MAX_ITERATIONS);
+ CASESTR(STAGNATION);
+ CASESTR(FAILURE);
default:
return "UNKNOWN";
}
}
#undef CASESTR
+#undef STRENUM
bool IsSchurType(LinearSolverType type) {
return ((type == SPARSE_SCHUR) ||
@@ -128,4 +250,26 @@ bool IsSchurType(LinearSolverType type) {
(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;
+}
+
} // namespace ceres
diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility.cc b/extern/libmv/third_party/ceres/internal/ceres/visibility.cc
index 564cc54493e..8e80fd121bb 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/visibility.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/visibility.cc
@@ -28,6 +28,8 @@
//
// Author: kushalav@google.com (Avanish Kushal)
+#include "ceres/visibility.h"
+
#include <cmath>
#include <ctime>
#include <algorithm>
@@ -36,7 +38,6 @@
#include <utility>
#include "ceres/block_structure.h"
#include "ceres/collections_port.h"
-#include "ceres/visibility.h"
#include "ceres/graph.h"
#include "glog/logging.h"
diff --git a/extern/libmv/third_party/ceres/internal/ceres/visibility.h b/extern/libmv/third_party/ceres/internal/ceres/visibility.h
index 692dd87201e..f29e3c6a0a8 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/visibility.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/visibility.h
@@ -42,7 +42,7 @@
namespace ceres {
namespace internal {
-class CompressedRowBlockStructure;
+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
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
index 4caad03d7a1..a75d6f0c17e 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc
+++ b/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc
@@ -65,17 +65,17 @@ static const double kSimilarityPenaltyWeight = 0.0;
#ifndef CERES_NO_SUITESPARSE
VisibilityBasedPreconditioner::VisibilityBasedPreconditioner(
const CompressedRowBlockStructure& bs,
- const LinearSolver::Options& options)
+ const Preconditioner::Options& options)
: options_(options),
num_blocks_(0),
num_clusters_(0),
factor_(NULL) {
- CHECK_GT(options_.num_eliminate_blocks, 0);
- CHECK(options_.preconditioner_type == SCHUR_JACOBI ||
- options_.preconditioner_type == CLUSTER_JACOBI ||
- options_.preconditioner_type == CLUSTER_TRIDIAGONAL)
- << "Unknown preconditioner type: " << options_.preconditioner_type;
- num_blocks_ = bs.cols.size() - options_.num_eliminate_blocks;
+ 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.";
@@ -83,14 +83,11 @@ VisibilityBasedPreconditioner::VisibilityBasedPreconditioner(
// 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_.num_eliminate_blocks].size;
+ block_size_[i] = bs.cols[i + options_.elimination_groups[0]].size;
}
const time_t start_time = time(NULL);
- switch (options_.preconditioner_type) {
- case SCHUR_JACOBI:
- ComputeSchurJacobiSparsity(bs);
- break;
+ switch (options_.type) {
case CLUSTER_JACOBI:
ComputeClusterJacobiSparsity(bs);
break;
@@ -130,24 +127,6 @@ VisibilityBasedPreconditioner::~VisibilityBasedPreconditioner() {
}
}
-// Determine the sparsity structure of the SCHUR_JACOBI
-// preconditioner. SCHUR_JACOBI is an extreme case of a visibility
-// based preconditioner where each camera block corresponds to a
-// cluster and there is no interaction between clusters.
-void VisibilityBasedPreconditioner::ComputeSchurJacobiSparsity(
- const CompressedRowBlockStructure& bs) {
- num_clusters_ = num_blocks_;
- cluster_membership_.resize(num_blocks_);
- cluster_pairs_.clear();
-
- // Each camea block is a member of its own cluster and the only
- // cluster pairs are the self edges (i,i).
- for (int i = 0; i < num_clusters_; ++i) {
- cluster_membership_[i] = i;
- cluster_pairs_.insert(make_pair(i, i));
- }
-}
-
// Determine the sparsity structure of the CLUSTER_JACOBI
// preconditioner. It clusters cameras using their scene
// visibility. The clusters form the diagonal blocks of the
@@ -155,7 +134,7 @@ void VisibilityBasedPreconditioner::ComputeSchurJacobiSparsity(
void VisibilityBasedPreconditioner::ComputeClusterJacobiSparsity(
const CompressedRowBlockStructure& bs) {
vector<set<int> > visibility;
- ComputeVisibility(bs, options_.num_eliminate_blocks, &visibility);
+ ComputeVisibility(bs, options_.elimination_groups[0], &visibility);
CHECK_EQ(num_blocks_, visibility.size());
ClusterCameras(visibility);
cluster_pairs_.clear();
@@ -173,7 +152,7 @@ void VisibilityBasedPreconditioner::ComputeClusterJacobiSparsity(
void VisibilityBasedPreconditioner::ComputeClusterTridiagonalSparsity(
const CompressedRowBlockStructure& bs) {
vector<set<int> > visibility;
- ComputeVisibility(bs, options_.num_eliminate_blocks, &visibility);
+ ComputeVisibility(bs, options_.elimination_groups[0], &visibility);
CHECK_EQ(num_blocks_, visibility.size());
ClusterCameras(visibility);
@@ -253,7 +232,7 @@ void VisibilityBasedPreconditioner::ComputeBlockPairsInPreconditioner(
int r = 0;
const int num_row_blocks = bs.rows.size();
- const int num_eliminate_blocks = options_.num_eliminate_blocks;
+ 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
@@ -331,16 +310,16 @@ void VisibilityBasedPreconditioner::ComputeBlockPairsInPreconditioner(
void VisibilityBasedPreconditioner::InitEliminator(
const CompressedRowBlockStructure& bs) {
LinearSolver::Options eliminator_options;
- eliminator_options.num_eliminate_blocks = options_.num_eliminate_blocks;
+ eliminator_options.elimination_groups = options_.elimination_groups;
eliminator_options.num_threads = options_.num_threads;
- DetectStructure(bs, options_.num_eliminate_blocks,
+ DetectStructure(bs, options_.elimination_groups[0],
&eliminator_options.row_block_size,
&eliminator_options.e_block_size,
&eliminator_options.f_block_size);
eliminator_.reset(SchurEliminatorBase::Create(eliminator_options));
- eliminator_->Init(options_.num_eliminate_blocks, &bs);
+ eliminator_->Init(options_.elimination_groups[0], &bs);
}
// Update the values of the preconditioner matrix and factorize it.
@@ -364,13 +343,13 @@ bool VisibilityBasedPreconditioner::Update(const BlockSparseMatrixBase& A,
// 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 SCHUR_JACOBI and 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
+ // 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".
//
@@ -380,10 +359,10 @@ bool VisibilityBasedPreconditioner::Update(const BlockSparseMatrixBase& A,
// 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 SCHUR_JACOBI
- // and the CLUSTER_JACOBI cases, the preconditioner is guaranteed to
- // be positive semidefinite.
- if (!status && options_.preconditioner_type == CLUSTER_TRIDIAGONAL) {
+ // belong to the edges of the degree-2 forest. In the CLUSTER_JACOBI
+ // case, the preconditioner is guaranteed to be positive
+ // semidefinite.
+ if (!status && options_.type == CLUSTER_TRIDIAGONAL) {
VLOG(1) << "Unscaled factorization failed. Retrying with off-diagonal "
<< "scaling";
ScaleOffDiagonalCells();
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
index 888c65eba3a..8a09c78d36a 100644
--- a/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h
+++ b/extern/libmv/third_party/ceres/internal/ceres/visibility_based_preconditioner.h
@@ -29,25 +29,19 @@
// Author: sameeragarwal@google.com (Sameer Agarwal)
//
// Preconditioners for linear systems that arise in Structure from
-// Motion problems. VisibilityBasedPreconditioner implements three
-// preconditioners:
+// Motion problems. VisibilityBasedPreconditioner implements:
//
-// SCHUR_JACOBI
// CLUSTER_JACOBI
// CLUSTER_TRIDIAGONAL
//
// 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
-//
// Visibility Based Preconditioning for Bundle Adjustment
// A. Kushal & S. Agarwal, submitted to CVPR 2012
// http://www.cs.washington.edu/homes/sagarwal/vbp.pdf
//
-// The three preconditioners share enough code that its most efficient
+// 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_
@@ -58,36 +52,26 @@
#include <utility>
#include "ceres/collections_port.h"
#include "ceres/graph.h"
-#include "ceres/linear_solver.h"
-#include "ceres/linear_operator.h"
-#include "ceres/suitesparse.h"
#include "ceres/internal/macros.h"
#include "ceres/internal/scoped_ptr.h"
+#include "ceres/preconditioner.h"
+#include "ceres/suitesparse.h"
namespace ceres {
namespace internal {
class BlockRandomAccessSparseMatrix;
class BlockSparseMatrixBase;
-class CompressedRowBlockStructure;
+struct CompressedRowBlockStructure;
class SchurEliminatorBase;
-// This class implements three preconditioners for Structure from
-// Motion/Bundle Adjustment problems. The name
+// 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.
//
-// Strictly speaking, SCHUR_JACOBI is not a visibility based
-// preconditioner but it is an extreme case of CLUSTER_JACOBI, where
-// every cluster contains exactly one camera block. Treating it as a
-// special case of CLUSTER_JACOBI makes it easy to implement as part
-// of the same code base with no significant loss of performance.
-//
-// In the following, we will only discuss CLUSTER_JACOBI and
-// CLUSTER_TRIDIAGONAL.
-//
// 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
@@ -130,15 +114,15 @@ class SchurEliminatorBase;
//
// LinearSolver::Options options;
// options.preconditioner_type = CLUSTER_JACOBI;
-// options.num_eliminate_blocks = num_points;
+// 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 LinearOperator {
+class VisibilityBasedPreconditioner : public Preconditioner {
public:
// Initialize the symbolic structure of the preconditioner. bs is
// the block structure of the linear system to be solved. It is used
@@ -146,48 +130,17 @@ class VisibilityBasedPreconditioner : public LinearOperator {
//
// It has the same structural requirement as other Schur complement
// based solvers. Please see schur_eliminator.h for more details.
- //
- // LinearSolver::Options::num_eliminate_blocks should be set to the
- // number of e_blocks in the block structure.
- //
- // TODO(sameeragarwal): The use of LinearSolver::Options should
- // ultimately be replaced with Preconditioner::Options and some sort
- // of preconditioner factory along the lines of
- // LinearSolver::CreateLinearSolver. I will wait to do this till I
- // create a general purpose block Jacobi preconditioner for general
- // sparse problems along with a CGLS solver.
VisibilityBasedPreconditioner(const CompressedRowBlockStructure& bs,
- const LinearSolver::Options& options);
+ const Preconditioner::Options& options);
virtual ~VisibilityBasedPreconditioner();
- // 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.
- bool Update(const BlockSparseMatrixBase& A, const double* D);
-
-
- // 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.
+ // Preconditioner interface
+ virtual bool Update(const BlockSparseMatrixBase& A, const double* D);
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;
- virtual int num_cols() const { return num_rows(); }
friend class VisibilityBasedPreconditionerTest;
private:
- void ComputeSchurJacobiSparsity(const CompressedRowBlockStructure& bs);
void ComputeClusterJacobiSparsity(const CompressedRowBlockStructure& bs);
void ComputeClusterTridiagonalSparsity(const CompressedRowBlockStructure& bs);
void InitStorage(const CompressedRowBlockStructure& bs);
@@ -207,7 +160,7 @@ class VisibilityBasedPreconditioner : public LinearOperator {
bool IsBlockPairInPreconditioner(int block1, int block2) const;
bool IsBlockPairOffDiagonal(int block1, int block2) const;
- LinearSolver::Options options_;
+ Preconditioner::Options options_;
// Number of parameter blocks in the schur complement.
int num_blocks_;
@@ -249,10 +202,10 @@ class VisibilityBasedPreconditioner : public LinearOperator {
#else // SuiteSparse
// If SuiteSparse is not compiled in, the preconditioner is not
// available.
-class VisibilityBasedPreconditioner : public LinearOperator {
+class VisibilityBasedPreconditioner : public Preconditioner {
public:
VisibilityBasedPreconditioner(const CompressedRowBlockStructure& bs,
- const LinearSolver::Options& options) {
+ const Preconditioner::Options& options) {
LOG(FATAL) << "Visibility based preconditioning is not available. Please "
"build Ceres with SuiteSparse.";
}
diff --git a/extern/libmv/third_party/ceres/internal/ceres/wall_time.cc b/extern/libmv/third_party/ceres/internal/ceres/wall_time.cc
new file mode 100644
index 00000000000..e63d20c0ab1
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/wall_time.cc
@@ -0,0 +1,96 @@
+// 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_,
+ " %25s : %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
new file mode 100644
index 00000000000..45f65ca1aa5
--- /dev/null
+++ b/extern/libmv/third_party/ceres/internal/ceres/wall_time.h
@@ -0,0 +1,88 @@
+// 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 "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/ceres/patches/collections_port.h.mingw.patch b/extern/libmv/third_party/ceres/patches/collections_port.h.mingw.patch
deleted file mode 100644
index c01a17c7992..00000000000
--- a/extern/libmv/third_party/ceres/patches/collections_port.h.mingw.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/internal/ceres/collections_port.h b/internal/ceres/collections_port.h
-index a356cc0..c2fce90 100644
---- a/internal/ceres/collections_port.h
-+++ b/internal/ceres/collections_port.h
-@@ -77,7 +77,7 @@ struct HashMap : std::tr1::unordered_map<K, V> {};
- template<typename K>
- struct HashSet : std::tr1::unordered_set<K> {};
-
--#ifdef _WIN32
-+#if defined(_WIN32) && !defined(__MINGW64__) && !defined(__MINGW32__)
- #define GG_LONGLONG(x) x##I64
- #define GG_ULONGLONG(x) x##UI64
- #else
diff --git a/extern/libmv/third_party/ceres/patches/msvc_glog_fix.patch b/extern/libmv/third_party/ceres/patches/msvc_glog_fix.patch
deleted file mode 100644
index f3200fb8e0a..00000000000
--- a/extern/libmv/third_party/ceres/patches/msvc_glog_fix.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-diff --git a/internal/ceres/block_random_access_dense_matrix.cc b/internal/ceres/block_random_access_dense_matrix.cc
-index aedfc74..0f95e89 100644
---- a/internal/ceres/block_random_access_dense_matrix.cc
-+++ b/internal/ceres/block_random_access_dense_matrix.cc
-@@ -28,12 +28,12 @@
- //
- // Author: sameeragarwal@google.com (Sameer Agarwal)
-
-+#include "glog/logging.h"
- #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 {
-diff --git a/internal/ceres/block_random_access_sparse_matrix.cc b/internal/ceres/block_random_access_sparse_matrix.cc
-index f789436..9ed62ce 100644
---- a/internal/ceres/block_random_access_sparse_matrix.cc
-+++ b/internal/ceres/block_random_access_sparse_matrix.cc
-@@ -28,6 +28,7 @@
- //
- // Author: sameeragarwal@google.com (Sameer Agarwal)
-
-+#include "glog/logging.h"
- #include "ceres/block_random_access_sparse_matrix.h"
-
- #include <algorithm>
-@@ -39,7 +40,6 @@
- #include "ceres/mutex.h"
- #include "ceres/triplet_sparse_matrix.h"
- #include "ceres/types.h"
--#include "glog/logging.h"
-
- namespace ceres {
- namespace internal {
-diff --git a/internal/ceres/schur_complement_solver.cc b/internal/ceres/schur_complement_solver.cc
-index b9224d8..2cbe78d 100644
---- a/internal/ceres/schur_complement_solver.cc
-+++ b/internal/ceres/schur_complement_solver.cc
-@@ -38,6 +38,7 @@
- #endif // CERES_NO_CXSPARSE
-
- #include "Eigen/Dense"
-+#include "glog/logging.h"
- #include "ceres/block_random_access_dense_matrix.h"
- #include "ceres/block_random_access_matrix.h"
- #include "ceres/block_random_access_sparse_matrix.h"
diff --git a/extern/libmv/third_party/ceres/patches/no_previous_declaration_fix.patch b/extern/libmv/third_party/ceres/patches/no_previous_declaration_fix.patch
deleted file mode 100644
index 03f1c500d9a..00000000000
--- a/extern/libmv/third_party/ceres/patches/no_previous_declaration_fix.patch
+++ /dev/null
@@ -1,199 +0,0 @@
-diff --git a/internal/ceres/file.cc b/internal/ceres/file.cc
-index 387f359..6fe7557 100644
---- a/internal/ceres/file.cc
-+++ b/internal/ceres/file.cc
-@@ -31,6 +31,7 @@
- // Really simple file IO.
-
- #include <cstdio>
-+#include "file.h"
- #include "glog/logging.h"
-
- namespace ceres {
-diff --git a/internal/ceres/linear_least_squares_problems.cc b/internal/ceres/linear_least_squares_problems.cc
-index 3e3bcd0..a91e254 100644
---- a/internal/ceres/linear_least_squares_problems.cc
-+++ b/internal/ceres/linear_least_squares_problems.cc
-@@ -573,13 +573,13 @@ LinearLeastSquaresProblem* LinearLeastSquaresProblem3() {
- return problem;
- }
-
--bool DumpLinearLeastSquaresProblemToConsole(const string& directory,
-- int iteration,
-- const SparseMatrix* A,
-- const double* D,
-- const double* b,
-- const double* x,
-- int num_eliminate_blocks) {
-+static bool DumpLinearLeastSquaresProblemToConsole(const string& directory,
-+ int iteration,
-+ const SparseMatrix* A,
-+ const double* D,
-+ const double* b,
-+ const double* x,
-+ int num_eliminate_blocks) {
- CHECK_NOTNULL(A);
- Matrix AA;
- A->ToDenseMatrix(&AA);
-@@ -601,13 +601,13 @@ bool DumpLinearLeastSquaresProblemToConsole(const string& directory,
- };
-
- #ifndef CERES_NO_PROTOCOL_BUFFERS
--bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
-- int iteration,
-- const SparseMatrix* A,
-- const double* D,
-- const double* b,
-- const double* x,
-- int num_eliminate_blocks) {
-+static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
-+ int iteration,
-+ const SparseMatrix* A,
-+ const double* D,
-+ const double* b,
-+ const double* x,
-+ int num_eliminate_blocks) {
- CHECK_NOTNULL(A);
- LinearLeastSquaresProblemProto lsqp;
- A->ToProto(lsqp.mutable_a());
-@@ -641,13 +641,13 @@ bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
- return true;
- }
- #else
--bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
-- int iteration,
-- const SparseMatrix* A,
-- const double* D,
-- const double* b,
-- const double* x,
-- int num_eliminate_blocks) {
-+static bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
-+ int iteration,
-+ const SparseMatrix* A,
-+ const double* D,
-+ const double* b,
-+ const double* x,
-+ int num_eliminate_blocks) {
- LOG(ERROR) << "Dumping least squares problems is only "
- << "supported when Ceres is compiled with "
- << "protocol buffer support.";
-@@ -655,9 +655,9 @@ bool DumpLinearLeastSquaresProblemToProtocolBuffer(const string& directory,
- }
- #endif
-
--void WriteArrayToFileOrDie(const string& filename,
-- const double* x,
-- const int size) {
-+static 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");
-@@ -668,13 +668,13 @@ void WriteArrayToFileOrDie(const string& filename,
- fclose(fptr);
- }
-
--bool DumpLinearLeastSquaresProblemToTextFile(const string& directory,
-- int iteration,
-- const SparseMatrix* A,
-- const double* D,
-- const double* b,
-- const double* x,
-- int num_eliminate_blocks) {
-+static bool DumpLinearLeastSquaresProblemToTextFile(const string& directory,
-+ int iteration,
-+ const SparseMatrix* A,
-+ const double* D,
-+ const double* b,
-+ const double* x,
-+ int num_eliminate_blocks) {
- CHECK_NOTNULL(A);
- string format_string = JoinPath(directory,
- "lm_iteration_%03d");
-diff --git a/internal/ceres/residual_block_utils.cc b/internal/ceres/residual_block_utils.cc
-index ff18e21..9442bb2 100644
---- a/internal/ceres/residual_block_utils.cc
-+++ b/internal/ceres/residual_block_utils.cc
-@@ -63,7 +63,7 @@ void InvalidateEvaluation(const ResidualBlock& block,
-
- // 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) {
-+static void AppendArrayToString(const int size, const double* x, string* result) {
- for (int i = 0; i < size; ++i) {
- if (x == NULL) {
- StringAppendF(result, "Not Computed ");
-diff --git a/internal/ceres/solver_impl.cc b/internal/ceres/solver_impl.cc
-index 2802a75..8ef5b98 100644
---- a/internal/ceres/solver_impl.cc
-+++ b/internal/ceres/solver_impl.cc
-@@ -685,8 +685,8 @@ bool SolverImpl::ApplyUserOrdering(const ProblemImpl& problem_impl,
- // Find the minimum index of any parameter block to the given residual.
- // Parameter blocks that have indices greater than num_eliminate_blocks are
- // considered to have an index equal to num_eliminate_blocks.
--int MinParameterBlock(const ResidualBlock* residual_block,
-- int num_eliminate_blocks) {
-+static int MinParameterBlock(const ResidualBlock* residual_block,
-+ int num_eliminate_blocks) {
- int min_parameter_block_position = num_eliminate_blocks;
- for (int i = 0; i < residual_block->NumParameterBlocks(); ++i) {
- ParameterBlock* parameter_block = residual_block->parameter_blocks()[i];
-diff --git a/internal/ceres/split.cc b/internal/ceres/split.cc
-index 4fa1bd4..c65c8a5 100644
---- a/internal/ceres/split.cc
-+++ b/internal/ceres/split.cc
-@@ -31,6 +31,7 @@
- #include <string>
- #include <vector>
- #include <iterator>
-+#include "ceres/split.h"
- #include "ceres/internal/port.h"
-
- namespace ceres {
-diff --git a/internal/ceres/stringprintf.cc b/internal/ceres/stringprintf.cc
-index c0f3522..396a48b 100644
---- a/internal/ceres/stringprintf.cc
-+++ b/internal/ceres/stringprintf.cc
-@@ -34,6 +34,7 @@
- #include <string>
- #include <vector>
-
-+#include "ceres/stringprintf.h"
- #include "ceres/internal/port.h"
-
- namespace ceres {
-diff --git a/internal/ceres/types.cc b/internal/ceres/types.cc
-index 2e950c5..05e573f 100644
---- a/internal/ceres/types.cc
-+++ b/internal/ceres/types.cc
-@@ -98,7 +98,8 @@ const char* SolverTerminationTypeToString(
- }
- }
-
--const char* SparseLinearAlgebraTypeToString(
-+#if 0 /* UNUSED */
-+static const char* SparseLinearAlgebraTypeToString(
- SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type) {
- switch (sparse_linear_algebra_library_type) {
- CASESTR(CX_SPARSE);
-@@ -107,6 +108,7 @@ const char* SparseLinearAlgebraTypeToString(
- return "UNKNOWN";
- }
- }
-+#endif
-
- const char* TrustRegionStrategyTypeToString(
- TrustRegionStrategyType trust_region_strategy_type) {
-diff --git a/internal/ceres/visibility.cc b/internal/ceres/visibility.cc
-index 9d80654..564cc54 100644
---- a/internal/ceres/visibility.cc
-+++ b/internal/ceres/visibility.cc
-@@ -36,6 +36,7 @@
- #include <utility>
- #include "ceres/block_structure.h"
- #include "ceres/collections_port.h"
-+#include "ceres/visibility.h"
- #include "ceres/graph.h"
- #include "glog/logging.h"
-
diff --git a/extern/libmv/third_party/ceres/patches/series b/extern/libmv/third_party/ceres/patches/series
index a6874318923..e69de29bb2d 100644
--- a/extern/libmv/third_party/ceres/patches/series
+++ b/extern/libmv/third_party/ceres/patches/series
@@ -1,3 +0,0 @@
-collections_port.h.mingw.patch
-msvc_glog_fix.patch
-no_previous_declaration_fix.patch \ No newline at end of file
diff --git a/extern/libmv/third_party/ldl/CMakeLists.txt b/extern/libmv/third_party/ldl/CMakeLists.txt
deleted file mode 100644
index db2d40e2612..00000000000
--- a/extern/libmv/third_party/ldl/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-include_directories(../ufconfig)
-include_directories(Include)
-add_library(ldl Source/ldl.c)
-
-LIBMV_INSTALL_THIRD_PARTY_LIB(ldl)
diff --git a/extern/libmv/third_party/ldl/Doc/ChangeLog b/extern/libmv/third_party/ldl/Doc/ChangeLog
deleted file mode 100644
index 48c322d3e77..00000000000
--- a/extern/libmv/third_party/ldl/Doc/ChangeLog
+++ /dev/null
@@ -1,39 +0,0 @@
-May 31, 2007: version 2.0.0
-
- * C-callable 64-bit version added
-
- * ported to 64-bit MATLAB
-
- * subdirectories added (Source/, Include/, Lib/, Demo/, Doc/, MATLAB/)
-
-Dec 12, 2006: version 1.3.4
-
- * minor MATLAB cleanup
-
-Sept 11, 2006: version 1.3.1
-
- * The ldl m-file renamed to ldlsparse, to avoid name conflict with the
- new MATLAB ldl function (in MATLAB 7.3).
-
-Apr 30, 2006: version 1.3
-
- * requires AMD v2.0. ldlmain.c demo program modified, since AMD can now
- handle jumbled matrices. Minor change to Makefile.
-
-Aug 30, 2005:
-
- * Makefile changed to use ../UFconfig/UFconfig.mk. License changed to
- GNU LGPL.
-
-July 4, 2005:
-
- * user guide added. Since no changes to the code were made,
- the version number (1.1) and code release date (Apr 22, 2005)
- were left unchanged.
-
-Apr. 22, 2005: LDL v1.1 released.
-
- * No real changes were made. The code was revised so
- that each routine fits on a single page in the documentation.
-
-Dec 31, 2003: LDL v1.0 released.
diff --git a/extern/libmv/third_party/ldl/Doc/lesser.txt b/extern/libmv/third_party/ldl/Doc/lesser.txt
deleted file mode 100644
index 8add30ad590..00000000000
--- a/extern/libmv/third_party/ldl/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/libmv/third_party/ldl/Include/ldl.h b/extern/libmv/third_party/ldl/Include/ldl.h
deleted file mode 100644
index 5840be322f7..00000000000
--- a/extern/libmv/third_party/ldl/Include/ldl.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/* ========================================================================== */
-/* === ldl.h: include file for the LDL package ============================= */
-/* ========================================================================== */
-
-/* LDL Copyright (c) Timothy A Davis,
- * University of Florida. All Rights Reserved. See README for the License.
- */
-
-#include "UFconfig.h"
-
-#ifdef LDL_LONG
-#define LDL_int UF_long
-#define LDL_ID UF_long_id
-
-#define LDL_symbolic ldl_l_symbolic
-#define LDL_numeric ldl_l_numeric
-#define LDL_lsolve ldl_l_lsolve
-#define LDL_dsolve ldl_l_dsolve
-#define LDL_ltsolve ldl_l_ltsolve
-#define LDL_perm ldl_l_perm
-#define LDL_permt ldl_l_permt
-#define LDL_valid_perm ldl_l_valid_perm
-#define LDL_valid_matrix ldl_l_valid_matrix
-
-#else
-#define LDL_int int
-#define LDL_ID "%d"
-
-#define LDL_symbolic ldl_symbolic
-#define LDL_numeric ldl_numeric
-#define LDL_lsolve ldl_lsolve
-#define LDL_dsolve ldl_dsolve
-#define LDL_ltsolve ldl_ltsolve
-#define LDL_perm ldl_perm
-#define LDL_permt ldl_permt
-#define LDL_valid_perm ldl_valid_perm
-#define LDL_valid_matrix ldl_valid_matrix
-
-#endif
-
-/* ========================================================================== */
-/* === int version ========================================================== */
-/* ========================================================================== */
-
-void ldl_symbolic (int n, int Ap [ ], int Ai [ ], int Lp [ ],
- int Parent [ ], int Lnz [ ], int Flag [ ], int P [ ], int Pinv [ ]) ;
-
-int ldl_numeric (int n, int Ap [ ], int Ai [ ], double Ax [ ],
- int Lp [ ], int Parent [ ], int Lnz [ ], int Li [ ], double Lx [ ],
- double D [ ], double Y [ ], int Pattern [ ], int Flag [ ],
- int P [ ], int Pinv [ ]) ;
-
-void ldl_lsolve (int n, double X [ ], int Lp [ ], int Li [ ],
- double Lx [ ]) ;
-
-void ldl_dsolve (int n, double X [ ], double D [ ]) ;
-
-void ldl_ltsolve (int n, double X [ ], int Lp [ ], int Li [ ],
- double Lx [ ]) ;
-
-void ldl_perm (int n, double X [ ], double B [ ], int P [ ]) ;
-void ldl_permt (int n, double X [ ], double B [ ], int P [ ]) ;
-
-int ldl_valid_perm (int n, int P [ ], int Flag [ ]) ;
-int ldl_valid_matrix ( int n, int Ap [ ], int Ai [ ]) ;
-
-/* ========================================================================== */
-/* === long version ========================================================= */
-/* ========================================================================== */
-
-void ldl_l_symbolic (UF_long n, UF_long Ap [ ], UF_long Ai [ ], UF_long Lp [ ],
- UF_long Parent [ ], UF_long Lnz [ ], UF_long Flag [ ], UF_long P [ ],
- UF_long Pinv [ ]) ;
-
-UF_long ldl_l_numeric (UF_long n, UF_long Ap [ ], UF_long Ai [ ], double Ax [ ],
- UF_long Lp [ ], UF_long Parent [ ], UF_long Lnz [ ], UF_long Li [ ],
- double Lx [ ], double D [ ], double Y [ ], UF_long Pattern [ ],
- UF_long Flag [ ], UF_long P [ ], UF_long Pinv [ ]) ;
-
-void ldl_l_lsolve (UF_long n, double X [ ], UF_long Lp [ ], UF_long Li [ ],
- double Lx [ ]) ;
-
-void ldl_l_dsolve (UF_long n, double X [ ], double D [ ]) ;
-
-void ldl_l_ltsolve (UF_long n, double X [ ], UF_long Lp [ ], UF_long Li [ ],
- double Lx [ ]) ;
-
-void ldl_l_perm (UF_long n, double X [ ], double B [ ], UF_long P [ ]) ;
-void ldl_l_permt (UF_long n, double X [ ], double B [ ], UF_long P [ ]) ;
-
-UF_long ldl_l_valid_perm (UF_long n, UF_long P [ ], UF_long Flag [ ]) ;
-UF_long ldl_l_valid_matrix ( UF_long n, UF_long Ap [ ], UF_long Ai [ ]) ;
-
-/* ========================================================================== */
-/* === LDL version ========================================================== */
-/* ========================================================================== */
-
-#define LDL_DATE "Nov 1, 2007"
-#define LDL_VERSION_CODE(main,sub) ((main) * 1000 + (sub))
-#define LDL_MAIN_VERSION 2
-#define LDL_SUB_VERSION 0
-#define LDL_SUBSUB_VERSION 1
-#define LDL_VERSION LDL_VERSION_CODE(LDL_MAIN_VERSION,LDL_SUB_VERSION)
-
diff --git a/extern/libmv/third_party/ldl/README.libmv b/extern/libmv/third_party/ldl/README.libmv
deleted file mode 100644
index 64ece48a390..00000000000
--- a/extern/libmv/third_party/ldl/README.libmv
+++ /dev/null
@@ -1,10 +0,0 @@
-Project: LDL
-URL: http://www.cise.ufl.edu/research/sparse/ldl/
-License: LGPL2.1
-Upstream version: 2.0.1 (despite the ChangeLog saying 2.0.0)
-
-Local modifications:
-
- * Deleted everything except ldl.c, ldl.h, the license, the ChangeLog, and the
- README.
-
diff --git a/extern/libmv/third_party/ldl/README.txt b/extern/libmv/third_party/ldl/README.txt
deleted file mode 100644
index 7be8dd1f001..00000000000
--- a/extern/libmv/third_party/ldl/README.txt
+++ /dev/null
@@ -1,136 +0,0 @@
-LDL Version 2.0: a sparse LDL' factorization and solve package.
- Written in C, with both a C and MATLAB mexFunction interface.
-
-These routines are not terrifically fast (they do not use dense matrix kernels),
-but the code is very short and concise. The purpose is to illustrate the
-algorithms in a very concise and readable manner, primarily for educational
-purposes. Although the code is very concise, this package is slightly faster
-than the built-in sparse Cholesky factorization in MATLAB 6.5 (chol), when
-using the same input permutation.
-
-Requires UFconfig, in the ../UFconfig directory relative to this directory.
-
-Quick start (Unix, or Windows with Cygwin):
-
- To compile, test, and install LDL, you may wish to first obtain a copy of
- AMD v2.0 from http://www.cise.ufl.edu/research/sparse, and place it in the
- ../AMD directory, relative to this directory. Next, type "make", which
- will compile the LDL library and three demo main programs (one of which
- requires AMD). It will also compile the LDL MATLAB mexFunction (if you
- have MATLAB). Typing "make clean" will remove non-essential files.
- AMD v2.0 or later is required. Its use is optional.
-
-Quick start (for MATLAB users);
-
- To compile, test, and install the LDL mexFunctions (ldlsparse and
- ldlsymbol), start MATLAB in this directory and type ldl_install.
- This works on any system supported by MATLAB.
-
---------------------------------------------------------------------------------
-
-LDL Copyright (c) 2005 by Timothy A. Davis. All Rights Reserved.
-
-LDL License:
-
- Your use or distribution of LDL or any modified version of
- LDL implies that you agree to this License.
-
- 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:
-
- http://www.cise.ufl.edu/research/sparse/ldl
-
-Acknowledgements:
-
- This work was supported by the National Science Foundation, under
- grant CCR-0203270.
-
- Portions of this work were done while on sabbatical at Stanford University
- and Lawrence Berkeley National Laboratory (with funding from the SciDAC
- program). I would like to thank Gene Golub, Esmond Ng, and Horst Simon
- for making this sabbatical possible. I would like to thank Pete Stewart
- for his comments on a draft of this software and paper.
-
---------------------------------------------------------------------------------
-Files and directories in this distribution:
---------------------------------------------------------------------------------
-
- Documentation, and compiling:
-
- README.txt this file
- Makefile for compiling LDL
- ChangeLog changes since V1.0 (Dec 31, 2003)
- License license
- lesser.txt the GNU LGPL license
-
- ldl_userguide.pdf user guide in PDF
- ldl_userguide.ps user guide in postscript
- ldl_userguide.tex user guide in Latex
- ldl.bib bibliography for user guide
-
- The LDL library itself:
-
- ldl.c the C-callable routines
- ldl.h include file for any code that calls LDL
-
- A simple C main program that demonstrates how to use LDL:
-
- ldlsimple.c a stand-alone C program, uses the basic features of LDL
- ldlsimple.out output of ldlsimple
-
- ldllsimple.c long integer version of ldlsimple.c
-
- Demo C program, for testing LDL and providing an example of its use
-
- ldlmain.c a stand-alone C main program that uses and tests LDL
- Matrix a directory containing matrices used by ldlmain.c
- ldlmain.out output of ldlmain
- ldlamd.out output of ldlamd (ldlmain.c compiled with AMD)
- ldllamd.out output of ldllamd (ldlmain.c compiled with AMD, long)
-
- MATLAB-related, not required for use in a regular C program
-
- Contents.m a list of the MATLAB-callable routines
- ldl.m MATLAB help file for the LDL mexFunction
- ldldemo.m MATLAB demo of how to use the LDL mexFunction
- ldldemo.out diary output of ldldemo
- ldltest.m to test the LDL mexFunction
- ldltest.out diary output of ldltest
- ldlmex.c the LDL mexFunction for MATLAB
- ldlrow.m the numerical algorithm that LDL is based on
- ldlmain2.m compiles and runs ldlmain.c as a MATLAB mexFunction
- ldlmain2.out output of ldlmain2.m
- ldlsymbolmex.c symbolic factorization using LDL (see SYMBFACT, ETREE)
- ldlsymbol.m help file for the LDLSYMBOL mexFunction
-
- ldl_install.m compile, install, and test LDL functions
- ldl_make.m compile LDL (ldlsparse and ldlsymbol)
-
- ldlsparse.m help for ldlsparse
-
-See ldl.c for a description of how to use the code from a C program. Type
-"help ldl" in MATLAB for information on how to use LDL in a MATLAB program.
diff --git a/extern/libmv/third_party/ldl/Source/ldl.c b/extern/libmv/third_party/ldl/Source/ldl.c
deleted file mode 100644
index a9b35c846ef..00000000000
--- a/extern/libmv/third_party/ldl/Source/ldl.c
+++ /dev/null
@@ -1,507 +0,0 @@
-/* ========================================================================== */
-/* === ldl.c: sparse LDL' factorization and solve package =================== */
-/* ========================================================================== */
-
-/* LDL: a simple set of routines for sparse LDL' factorization. These routines
- * are not terrifically fast (they do not use dense matrix kernels), but the
- * code is very short. The purpose is to illustrate the algorithms in a very
- * concise manner, primarily for educational purposes. Although the code is
- * very concise, this package is slightly faster than the built-in sparse
- * Cholesky factorization in MATLAB 7.0 (chol), when using the same input
- * permutation.
- *
- * The routines compute the LDL' factorization of a real sparse symmetric
- * matrix A (or PAP' if a permutation P is supplied), and solve upper
- * and lower triangular systems with the resulting L and D factors. If A is
- * positive definite then the factorization will be accurate. A can be
- * indefinite (with negative values on the diagonal D), but in this case no
- * guarantee of accuracy is provided, since no numeric pivoting is performed.
- *
- * The n-by-n sparse matrix A is in compressed-column form. The nonzero values
- * in column j are stored in Ax [Ap [j] ... Ap [j+1]-1], with corresponding row
- * indices in Ai [Ap [j] ... Ap [j+1]-1]. Ap [0] = 0 is required, and thus
- * nz = Ap [n] is the number of nonzeros in A. Ap is an int array of size n+1.
- * The int array Ai and the double array Ax are of size nz. This data structure
- * is identical to the one used by MATLAB, except for the following
- * generalizations. The row indices in each column of A need not be in any
- * particular order, although they must be in the range 0 to n-1. Duplicate
- * entries can be present; any duplicates are summed. That is, if row index i
- * appears twice in a column j, then the value of A (i,j) is the sum of the two
- * entries. The data structure used here for the input matrix A is more
- * flexible than MATLAB's, which requires sorted columns with no duplicate
- * entries.
- *
- * Only the diagonal and upper triangular part of A (or PAP' if a permutation
- * P is provided) is accessed. The lower triangular parts of the matrix A or
- * PAP' can be present, but they are ignored.
- *
- * The optional input permutation is provided as an array P of length n. If
- * P [k] = j, the row and column j of A is the kth row and column of PAP'.
- * If P is present then the factorization is LDL' = PAP' or L*D*L' = A(P,P) in
- * 0-based MATLAB notation. If P is not present (a null pointer) then no
- * permutation is performed, and the factorization is LDL' = A.
- *
- * The lower triangular matrix L is stored in the same compressed-column
- * form (an int Lp array of size n+1, an int Li array of size Lp [n], and a
- * double array Lx of the same size as Li). It has a unit diagonal, which is
- * not stored. The row indices in each column of L are always returned in
- * ascending order, with no duplicate entries. This format is compatible with
- * MATLAB, except that it would be more convenient for MATLAB to include the
- * unit diagonal of L. Doing so here would add additional complexity to the
- * code, and is thus omitted in the interest of keeping this code short and
- * readable.
- *
- * The elimination tree is held in the Parent [0..n-1] array. It is normally
- * not required by the user, but it is required by ldl_numeric. The diagonal
- * matrix D is held as an array D [0..n-1] of size n.
- *
- * --------------------
- * C-callable routines:
- * --------------------
- *
- * ldl_symbolic: Given the pattern of A, computes the Lp and Parent arrays
- * required by ldl_numeric. Takes time proportional to the number of
- * nonzeros in L. Computes the inverse Pinv of P if P is provided.
- * Also returns Lnz, the count of nonzeros in each column of L below
- * the diagonal (this is not required by ldl_numeric).
- * ldl_numeric: Given the pattern and numerical values of A, the Lp array,
- * the Parent array, and P and Pinv if applicable, computes the
- * pattern and numerical values of L and D.
- * ldl_lsolve: Solves Lx=b for a dense vector b.
- * ldl_dsolve: Solves Dx=b for a dense vector b.
- * ldl_ltsolve: Solves L'x=b for a dense vector b.
- * ldl_perm: Computes x=Pb for a dense vector b.
- * ldl_permt: Computes x=P'b for a dense vector b.
- * ldl_valid_perm: checks the validity of a permutation vector
- * ldl_valid_matrix: checks the validity of the sparse matrix A
- *
- * ----------------------------
- * Limitations of this package:
- * ----------------------------
- *
- * In the interest of keeping this code simple and readable, ldl_symbolic and
- * ldl_numeric assume their inputs are valid. You can check your own inputs
- * prior to calling these routines with the ldl_valid_perm and ldl_valid_matrix
- * routines. Except for the two ldl_valid_* routines, no routine checks to see
- * if the array arguments are present (non-NULL). Like all C routines, no
- * routine can determine if the arrays are long enough and don't overlap.
- *
- * The ldl_numeric does check the numerical factorization, however. It returns
- * n if the factorization is successful. If D (k,k) is zero, then k is
- * returned, and L is only partially computed.
- *
- * No pivoting to control fill-in is performed, which is often critical for
- * obtaining good performance. I recommend that you compute the permutation P
- * using AMD or SYMAMD (approximate minimum degree ordering routines), or an
- * appropriate graph-partitioning based ordering. See the ldldemo.m routine for
- * an example in MATLAB, and the ldlmain.c stand-alone C program for examples of
- * how to find P. Routines for manipulating compressed-column matrices are
- * available in UMFPACK. AMD, SYMAMD, UMFPACK, and this LDL package are all
- * available at http://www.cise.ufl.edu/research/sparse.
- *
- * -------------------------
- * Possible simplifications:
- * -------------------------
- *
- * These routines could be made even simpler with a few additional assumptions.
- * If no input permutation were performed, the caller would have to permute the
- * matrix first, but the computation of Pinv, and the use of P and Pinv could be
- * removed. If only the diagonal and upper triangular part of A or PAP' are
- * present, then the tests in the "if (i < k)" statement in ldl_symbolic and
- * "if (i <= k)" in ldl_numeric, are always true, and could be removed (i can
- * equal k in ldl_symbolic, but then the body of the if statement would
- * correctly do no work since Flag [k] == k). If we could assume that no
- * duplicate entries are present, then the statement Y [i] += Ax [p] could be
- * replaced with Y [i] = Ax [p] in ldl_numeric.
- *
- * --------------------------
- * Description of the method:
- * --------------------------
- *
- * LDL computes the symbolic factorization by finding the pattern of L one row
- * at a time. It does this based on the following theory. Consider a sparse
- * system Lx=b, where L, x, and b, are all sparse, and where L comes from a
- * Cholesky (or LDL') factorization. The elimination tree (etree) of L is
- * defined as follows. The parent of node j is the smallest k > j such that
- * L (k,j) is nonzero. Node j has no parent if column j of L is completely zero
- * below the diagonal (j is a root of the etree in this case). The nonzero
- * pattern of x is the union of the paths from each node i to the root, for
- * each nonzero b (i). To compute the numerical solution to Lx=b, we can
- * traverse the columns of L corresponding to nonzero values of x. This
- * traversal does not need to be done in the order 0 to n-1. It can be done in
- * any "topological" order, such that x (i) is computed before x (j) if i is a
- * descendant of j in the elimination tree.
- *
- * The row-form of the LDL' factorization is shown in the MATLAB function
- * ldlrow.m in this LDL package. Note that row k of L is found via a sparse
- * triangular solve of L (1:k-1, 1:k-1) \ A (1:k-1, k), to use 1-based MATLAB
- * notation. Thus, we can start with the nonzero pattern of the kth column of
- * A (above the diagonal), follow the paths up to the root of the etree of the
- * (k-1)-by-(k-1) leading submatrix of L, and obtain the pattern of the kth row
- * of L. Note that we only need the leading (k-1)-by-(k-1) submatrix of L to
- * do this. The elimination tree can be constructed as we go.
- *
- * The symbolic factorization does the same thing, except that it discards the
- * pattern of L as it is computed. It simply counts the number of nonzeros in
- * each column of L and then constructs the Lp index array when it's done. The
- * symbolic factorization does not need to do this in topological order.
- * Compare ldl_symbolic with the first part of ldl_numeric, and note that the
- * while (len > 0) loop is not present in ldl_symbolic.
- *
- * LDL Version 1.3, Copyright (c) 2006 by Timothy A Davis,
- * University of Florida. All Rights Reserved. Developed while on sabbatical
- * at Stanford University and Lawrence Berkeley National Laboratory. Refer to
- * the README file for the License. Available at
- * http://www.cise.ufl.edu/research/sparse.
- */
-
-#include "ldl.h"
-
-/* ========================================================================== */
-/* === ldl_symbolic ========================================================= */
-/* ========================================================================== */
-
-/* The input to this routine is a sparse matrix A, stored in column form, and
- * an optional permutation P. The output is the elimination tree
- * and the number of nonzeros in each column of L. Parent [i] = k if k is the
- * parent of i in the tree. The Parent array is required by ldl_numeric.
- * Lnz [k] gives the number of nonzeros in the kth column of L, excluding the
- * diagonal.
- *
- * One workspace vector (Flag) of size n is required.
- *
- * If P is NULL, then it is ignored. The factorization will be LDL' = A.
- * Pinv is not computed. In this case, neither P nor Pinv are required by
- * ldl_numeric.
- *
- * If P is not NULL, then it is assumed to be a valid permutation. If
- * row and column j of A is the kth pivot, the P [k] = j. The factorization
- * will be LDL' = PAP', or A (p,p) in MATLAB notation. The inverse permutation
- * Pinv is computed, where Pinv [j] = k if P [k] = j. In this case, both P
- * and Pinv are required as inputs to ldl_numeric.
- *
- * The floating-point operation count of the subsequent call to ldl_numeric
- * is not returned, but could be computed after ldl_symbolic is done. It is
- * the sum of (Lnz [k]) * (Lnz [k] + 2) for k = 0 to n-1.
- */
-
-void LDL_symbolic
-(
- LDL_int n, /* A and L are n-by-n, where n >= 0 */
- LDL_int Ap [ ], /* input of size n+1, not modified */
- LDL_int Ai [ ], /* input of size nz=Ap[n], not modified */
- LDL_int Lp [ ], /* output of size n+1, not defined on input */
- LDL_int Parent [ ], /* output of size n, not defined on input */
- LDL_int Lnz [ ], /* output of size n, not defined on input */
- LDL_int Flag [ ], /* workspace of size n, not defn. on input or output */
- LDL_int P [ ], /* optional input of size n */
- LDL_int Pinv [ ] /* optional output of size n (used if P is not NULL) */
-)
-{
- LDL_int i, k, p, kk, p2 ;
- if (P)
- {
- /* If P is present then compute Pinv, the inverse of P */
- for (k = 0 ; k < n ; k++)
- {
- Pinv [P [k]] = k ;
- }
- }
- for (k = 0 ; k < n ; k++)
- {
- /* L(k,:) pattern: all nodes reachable in etree from nz in A(0:k-1,k) */
- Parent [k] = -1 ; /* parent of k is not yet known */
- Flag [k] = k ; /* mark node k as visited */
- Lnz [k] = 0 ; /* count of nonzeros in column k of L */
- kk = (P) ? (P [k]) : (k) ; /* kth original, or permuted, column */
- p2 = Ap [kk+1] ;
- for (p = Ap [kk] ; p < p2 ; p++)
- {
- /* A (i,k) is nonzero (original or permuted A) */
- i = (Pinv) ? (Pinv [Ai [p]]) : (Ai [p]) ;
- if (i < k)
- {
- /* follow path from i to root of etree, stop at flagged node */
- for ( ; Flag [i] != k ; i = Parent [i])
- {
- /* find parent of i if not yet determined */
- if (Parent [i] == -1) Parent [i] = k ;
- Lnz [i]++ ; /* L (k,i) is nonzero */
- Flag [i] = k ; /* mark i as visited */
- }
- }
- }
- }
- /* construct Lp index array from Lnz column counts */
- Lp [0] = 0 ;
- for (k = 0 ; k < n ; k++)
- {
- Lp [k+1] = Lp [k] + Lnz [k] ;
- }
-}
-
-
-/* ========================================================================== */
-/* === ldl_numeric ========================================================== */
-/* ========================================================================== */
-
-/* Given a sparse matrix A (the arguments n, Ap, Ai, and Ax) and its symbolic
- * analysis (Lp and Parent, and optionally P and Pinv), compute the numeric LDL'
- * factorization of A or PAP'. The outputs of this routine are arguments Li,
- * Lx, and D. It also requires three size-n workspaces (Y, Pattern, and Flag).
- */
-
-LDL_int LDL_numeric /* returns n if successful, k if D (k,k) is zero */
-(
- LDL_int n, /* A and L are n-by-n, where n >= 0 */
- LDL_int Ap [ ], /* input of size n+1, not modified */
- LDL_int Ai [ ], /* input of size nz=Ap[n], not modified */
- double Ax [ ], /* input of size nz=Ap[n], not modified */
- LDL_int Lp [ ], /* input of size n+1, not modified */
- LDL_int Parent [ ], /* input of size n, not modified */
- LDL_int Lnz [ ], /* output of size n, not defn. on input */
- LDL_int Li [ ], /* output of size lnz=Lp[n], not defined on input */
- double Lx [ ], /* output of size lnz=Lp[n], not defined on input */
- double D [ ], /* output of size n, not defined on input */
- double Y [ ], /* workspace of size n, not defn. on input or output */
- LDL_int Pattern [ ],/* workspace of size n, not defn. on input or output */
- LDL_int Flag [ ], /* workspace of size n, not defn. on input or output */
- LDL_int P [ ], /* optional input of size n */
- LDL_int Pinv [ ] /* optional input of size n */
-)
-{
- double yi, l_ki ;
- LDL_int i, k, p, kk, p2, len, top ;
- for (k = 0 ; k < n ; k++)
- {
- /* compute nonzero Pattern of kth row of L, in topological order */
- Y [k] = 0.0 ; /* Y(0:k) is now all zero */
- top = n ; /* stack for pattern is empty */
- Flag [k] = k ; /* mark node k as visited */
- Lnz [k] = 0 ; /* count of nonzeros in column k of L */
- kk = (P) ? (P [k]) : (k) ; /* kth original, or permuted, column */
- p2 = Ap [kk+1] ;
- for (p = Ap [kk] ; p < p2 ; p++)
- {
- i = (Pinv) ? (Pinv [Ai [p]]) : (Ai [p]) ; /* get A(i,k) */
- if (i <= k)
- {
- Y [i] += Ax [p] ; /* scatter A(i,k) into Y (sum duplicates) */
- for (len = 0 ; Flag [i] != k ; i = Parent [i])
- {
- Pattern [len++] = i ; /* L(k,i) is nonzero */
- Flag [i] = k ; /* mark i as visited */
- }
- while (len > 0) Pattern [--top] = Pattern [--len] ;
- }
- }
- /* compute numerical values kth row of L (a sparse triangular solve) */
- D [k] = Y [k] ; /* get D(k,k) and clear Y(k) */
- Y [k] = 0.0 ;
- for ( ; top < n ; top++)
- {
- i = Pattern [top] ; /* Pattern [top:n-1] is pattern of L(:,k) */
- yi = Y [i] ; /* get and clear Y(i) */
- Y [i] = 0.0 ;
- p2 = Lp [i] + Lnz [i] ;
- for (p = Lp [i] ; p < p2 ; p++)
- {
- Y [Li [p]] -= Lx [p] * yi ;
- }
- l_ki = yi / D [i] ; /* the nonzero entry L(k,i) */
- D [k] -= l_ki * yi ;
- Li [p] = k ; /* store L(k,i) in column form of L */
- Lx [p] = l_ki ;
- Lnz [i]++ ; /* increment count of nonzeros in col i */
- }
- if (D [k] == 0.0) return (k) ; /* failure, D(k,k) is zero */
- }
- return (n) ; /* success, diagonal of D is all nonzero */
-}
-
-
-/* ========================================================================== */
-/* === ldl_lsolve: solve Lx=b ============================================== */
-/* ========================================================================== */
-
-void LDL_lsolve
-(
- LDL_int n, /* L is n-by-n, where n >= 0 */
- double X [ ], /* size n. right-hand-side on input, soln. on output */
- LDL_int Lp [ ], /* input of size n+1, not modified */
- LDL_int Li [ ], /* input of size lnz=Lp[n], not modified */
- double Lx [ ] /* input of size lnz=Lp[n], not modified */
-)
-{
- LDL_int j, p, p2 ;
- for (j = 0 ; j < n ; j++)
- {
- p2 = Lp [j+1] ;
- for (p = Lp [j] ; p < p2 ; p++)
- {
- X [Li [p]] -= Lx [p] * X [j] ;
- }
- }
-}
-
-
-/* ========================================================================== */
-/* === ldl_dsolve: solve Dx=b ============================================== */
-/* ========================================================================== */
-
-void LDL_dsolve
-(
- LDL_int n, /* D is n-by-n, where n >= 0 */
- double X [ ], /* size n. right-hand-side on input, soln. on output */
- double D [ ] /* input of size n, not modified */
-)
-{
- LDL_int j ;
- for (j = 0 ; j < n ; j++)
- {
- X [j] /= D [j] ;
- }
-}
-
-
-/* ========================================================================== */
-/* === ldl_ltsolve: solve L'x=b ============================================ */
-/* ========================================================================== */
-
-void LDL_ltsolve
-(
- LDL_int n, /* L is n-by-n, where n >= 0 */
- double X [ ], /* size n. right-hand-side on input, soln. on output */
- LDL_int Lp [ ], /* input of size n+1, not modified */
- LDL_int Li [ ], /* input of size lnz=Lp[n], not modified */
- double Lx [ ] /* input of size lnz=Lp[n], not modified */
-)
-{
- int j, p, p2 ;
- for (j = n-1 ; j >= 0 ; j--)
- {
- p2 = Lp [j+1] ;
- for (p = Lp [j] ; p < p2 ; p++)
- {
- X [j] -= Lx [p] * X [Li [p]] ;
- }
- }
-}
-
-
-/* ========================================================================== */
-/* === ldl_perm: permute a vector, x=Pb ===================================== */
-/* ========================================================================== */
-
-void LDL_perm
-(
- LDL_int n, /* size of X, B, and P */
- double X [ ], /* output of size n. */
- double B [ ], /* input of size n. */
- LDL_int P [ ] /* input permutation array of size n. */
-)
-{
- LDL_int j ;
- for (j = 0 ; j < n ; j++)
- {
- X [j] = B [P [j]] ;
- }
-}
-
-
-/* ========================================================================== */
-/* === ldl_permt: permute a vector, x=P'b =================================== */
-/* ========================================================================== */
-
-void LDL_permt
-(
- LDL_int n, /* size of X, B, and P */
- double X [ ], /* output of size n. */
- double B [ ], /* input of size n. */
- LDL_int P [ ] /* input permutation array of size n. */
-)
-{
- LDL_int j ;
- for (j = 0 ; j < n ; j++)
- {
- X [P [j]] = B [j] ;
- }
-}
-
-
-/* ========================================================================== */
-/* === ldl_valid_perm: check if a permutation vector is valid =============== */
-/* ========================================================================== */
-
-LDL_int LDL_valid_perm /* returns 1 if valid, 0 otherwise */
-(
- LDL_int n,
- LDL_int P [ ], /* input of size n, a permutation of 0:n-1 */
- LDL_int Flag [ ] /* workspace of size n */
-)
-{
- LDL_int j, k ;
- if (n < 0 || !Flag)
- {
- return (0) ; /* n must be >= 0, and Flag must be present */
- }
- if (!P)
- {
- return (1) ; /* If NULL, P is assumed to be the identity perm. */
- }
- for (j = 0 ; j < n ; j++)
- {
- Flag [j] = 0 ; /* clear the Flag array */
- }
- for (k = 0 ; k < n ; k++)
- {
- j = P [k] ;
- if (j < 0 || j >= n || Flag [j] != 0)
- {
- return (0) ; /* P is not valid */
- }
- Flag [j] = 1 ;
- }
- return (1) ; /* P is valid */
-}
-
-
-/* ========================================================================== */
-/* === ldl_valid_matrix: check if a sparse matrix is valid ================== */
-/* ========================================================================== */
-
-/* This routine checks to see if a sparse matrix A is valid for input to
- * ldl_symbolic and ldl_numeric. It returns 1 if the matrix is valid, 0
- * otherwise. A is in sparse column form. The numerical values in column j
- * are stored in Ax [Ap [j] ... Ap [j+1]-1], with row indices in
- * Ai [Ap [j] ... Ap [j+1]-1]. The Ax array is not checked.
- */
-
-LDL_int LDL_valid_matrix
-(
- LDL_int n,
- LDL_int Ap [ ],
- LDL_int Ai [ ]
-)
-{
- LDL_int j, p ;
- if (n < 0 || !Ap || !Ai || Ap [0] != 0)
- {
- return (0) ; /* n must be >= 0, and Ap and Ai must be present */
- }
- for (j = 0 ; j < n ; j++)
- {
- if (Ap [j] > Ap [j+1])
- {
- return (0) ; /* Ap must be monotonically nondecreasing */
- }
- }
- for (p = 0 ; p < Ap [n] ; p++)
- {
- if (Ai [p] < 0 || Ai [p] >= n)
- {
- return (0) ; /* row indices must be in the range 0 to n-1 */
- }
- }
- return (1) ; /* matrix is valid */
-}
diff --git a/extern/libmv/third_party/ssba/COPYING.TXT b/extern/libmv/third_party/ssba/COPYING.TXT
deleted file mode 100644
index fc8a5de7edf..00000000000
--- a/extern/libmv/third_party/ssba/COPYING.TXT
+++ /dev/null
@@ -1,165 +0,0 @@
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-
- This version of the GNU Lesser General Public License incorporates
-the terms and conditions of version 3 of the GNU General Public
-License, supplemented by the additional permissions listed below.
-
- 0. Additional Definitions.
-
- As used herein, "this License" refers to version 3 of the GNU Lesser
-General Public License, and the "GNU GPL" refers to version 3 of the GNU
-General Public License.
-
- "The Library" refers to a covered work governed by this License,
-other than an Application or a Combined Work as defined below.
-
- An "Application" is any work that makes use of an interface provided
-by the Library, but which is not otherwise based on the Library.
-Defining a subclass of a class defined by the Library is deemed a mode
-of using an interface provided by the Library.
-
- A "Combined Work" is a work produced by combining or linking an
-Application with the Library. The particular version of the Library
-with which the Combined Work was made is also called the "Linked
-Version".
-
- The "Minimal Corresponding Source" for a Combined Work means the
-Corresponding Source for the Combined Work, excluding any source code
-for portions of the Combined Work that, considered in isolation, are
-based on the Application, and not on the Linked Version.
-
- The "Corresponding Application Code" for a Combined Work means the
-object code and/or source code for the Application, including any data
-and utility programs needed for reproducing the Combined Work from the
-Application, but excluding the System Libraries of the Combined Work.
-
- 1. Exception to Section 3 of the GNU GPL.
-
- You may convey a covered work under sections 3 and 4 of this License
-without being bound by section 3 of the GNU GPL.
-
- 2. Conveying Modified Versions.
-
- If you modify a copy of the Library, and, in your modifications, a
-facility refers to a function or data to be supplied by an Application
-that uses the facility (other than as an argument passed when the
-facility is invoked), then you may convey a copy of the modified
-version:
-
- a) under this License, provided that you make a good faith effort to
- ensure that, in the event an Application does not supply the
- function or data, the facility still operates, and performs
- whatever part of its purpose remains meaningful, or
-
- b) under the GNU GPL, with none of the additional permissions of
- this License applicable to that copy.
-
- 3. Object Code Incorporating Material from Library Header Files.
-
- The object code form of an Application may incorporate material from
-a header file that is part of the Library. You may convey such object
-code under terms of your choice, provided that, if the incorporated
-material is not limited to numerical parameters, data structure
-layouts and accessors, or small macros, inline functions and templates
-(ten or fewer lines in length), you do both of the following:
-
- a) Give prominent notice with each copy of the object code that the
- Library is used in it and that the Library and its use are
- covered by this License.
-
- b) Accompany the object code with a copy of the GNU GPL and this license
- document.
-
- 4. Combined Works.
-
- You may convey a Combined Work under terms of your choice that,
-taken together, effectively do not restrict modification of the
-portions of the Library contained in the Combined Work and reverse
-engineering for debugging such modifications, if you also do each of
-the following:
-
- a) Give prominent notice with each copy of the Combined Work that
- the Library is used in it and that the Library and its use are
- covered by this License.
-
- b) Accompany the Combined Work with a copy of the GNU GPL and this license
- document.
-
- c) For a Combined Work that displays copyright notices during
- execution, include the copyright notice for the Library among
- these notices, as well as a reference directing the user to the
- copies of the GNU GPL and this license document.
-
- d) Do one of the following:
-
- 0) Convey the Minimal Corresponding Source under the terms of this
- License, and the Corresponding Application Code in a form
- suitable for, and under terms that permit, the user to
- recombine or relink the Application with a modified version of
- the Linked Version to produce a modified Combined Work, in the
- manner specified by section 6 of the GNU GPL for conveying
- Corresponding Source.
-
- 1) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (a) uses at run time
- a copy of the Library already present on the user's computer
- system, and (b) will operate properly with a modified version
- of the Library that is interface-compatible with the Linked
- Version.
-
- e) Provide Installation Information, but only if you would otherwise
- be required to provide such information under section 6 of the
- GNU GPL, and only to the extent that such information is
- necessary to install and execute a modified version of the
- Combined Work produced by recombining or relinking the
- Application with a modified version of the Linked Version. (If
- you use option 4d0, the Installation Information must accompany
- the Minimal Corresponding Source and Corresponding Application
- Code. If you use option 4d1, you must provide the Installation
- Information in the manner specified by section 6 of the GNU GPL
- for conveying Corresponding Source.)
-
- 5. Combined Libraries.
-
- 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 that are not Applications and are not covered by this
-License, and convey such a combined library under terms of your
-choice, if you do both of the following:
-
- a) Accompany the combined library with a copy of the same work based
- on the Library, uncombined with any other library facilities,
- conveyed under the terms of this License.
-
- b) Give prominent notice with the combined library that part of it
- is a work based on the Library, and explaining where to find the
- accompanying uncombined form of the same work.
-
- 6. Revised Versions of the GNU Lesser General Public License.
-
- The Free Software Foundation may publish revised and/or new versions
-of the GNU 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 as you received it specifies that a certain numbered version
-of the GNU Lesser General Public License "or any later version"
-applies to it, you have the option of following the terms and
-conditions either of that published version or of any later version
-published by the Free Software Foundation. If the Library as you
-received it does not specify a version number of the GNU Lesser
-General Public License, you may choose any version of the GNU Lesser
-General Public License ever published by the Free Software Foundation.
-
- If the Library as you received it specifies that a proxy can decide
-whether future versions of the GNU Lesser General Public License shall
-apply, that proxy's public statement of acceptance of any version is
-permanent authorization for you to choose that version for the
-Library.
diff --git a/extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h b/extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h
deleted file mode 100644
index 448ae9714e5..00000000000
--- a/extern/libmv/third_party/ssba/Geometry/v3d_cameramatrix.h
+++ /dev/null
@@ -1,204 +0,0 @@
-// -*- C++ -*-
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA 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.
-
-SSBA is distributed in the hope that 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 SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef V3D_CAMERA_MATRIX_H
-#define V3D_CAMERA_MATRIX_H
-
-#include "Math/v3d_linear.h"
-#include "Geometry/v3d_distortion.h"
-
-namespace V3D
-{
-
- struct CameraMatrix
- {
- CameraMatrix()
- {
- makeIdentityMatrix(_K);
- makeIdentityMatrix(_R);
- makeZeroVector(_T);
- this->updateCachedValues(true, true);
- }
-
- CameraMatrix(double f, double cx, double cy)
- {
- makeIdentityMatrix(_K);
- _K[0][0] = f;
- _K[1][1] = f;
- _K[0][2] = cx;
- _K[1][2] = cy;
- makeIdentityMatrix(_R);
- makeZeroVector(_T);
- this->updateCachedValues(true, true);
- }
-
- CameraMatrix(Matrix3x3d const& K,
- Matrix3x3d const& R,
- Vector3d const& T)
- : _K(K), _R(R), _T(T)
- {
- this->updateCachedValues(true, true);
- }
-
- void setIntrinsic(Matrix3x3d const& K) { _K = K; this->updateCachedValues(true, false); }
- void setRotation(Matrix3x3d const& R) { _R = R; this->updateCachedValues(false, true); }
- void setTranslation(Vector3d const& T) { _T = T; this->updateCachedValues(false, true); }
-
- template <typename Mat>
- void setOrientation(Mat const& RT)
- {
- _R[0][0] = RT[0][0]; _R[0][1] = RT[0][1]; _R[0][2] = RT[0][2];
- _R[1][0] = RT[1][0]; _R[1][1] = RT[1][1]; _R[1][2] = RT[1][2];
- _R[2][0] = RT[2][0]; _R[2][1] = RT[2][1]; _R[2][2] = RT[2][2];
- _T[0] = RT[0][3]; _T[1] = RT[1][3]; _T[2] = RT[2][3];
- this->updateCachedValues(false, true);
- }
-
- Matrix3x3d const& getIntrinsic() const { return _K; }
- Matrix3x3d const& getRotation() const { return _R; }
- Vector3d const& getTranslation() const { return _T; }
-
- Matrix3x4d getOrientation() const
- {
- Matrix3x4d RT;
- RT[0][0] = _R[0][0]; RT[0][1] = _R[0][1]; RT[0][2] = _R[0][2];
- RT[1][0] = _R[1][0]; RT[1][1] = _R[1][1]; RT[1][2] = _R[1][2];
- RT[2][0] = _R[2][0]; RT[2][1] = _R[2][1]; RT[2][2] = _R[2][2];
- RT[0][3] = _T[0]; RT[1][3] = _T[1]; RT[2][3] = _T[2];
- return RT;
- }
-
- Matrix3x4d getProjection() const
- {
- Matrix3x4d const RT = this->getOrientation();
- return _K * RT;
- }
-
- double getFocalLength() const { return _K[0][0]; }
- double getAspectRatio() const { return _K[1][1] / _K[0][0]; }
-
- Vector2d getPrincipalPoint() const
- {
- Vector2d pp;
- pp[0] = _K[0][2];
- pp[1] = _K[1][2];
- return pp;
- }
-
- Vector2d projectPoint(Vector3d const& X) const
- {
- Vector3d q = _K*(_R*X + _T);
- Vector2d res;
- res[0] = q[0]/q[2]; res[1] = q[1]/q[2];
- return res;
- }
-
- template <typename Distortion>
- Vector2d projectPoint(Distortion const& distortion, Vector3d const& X) const
- {
- Vector3d XX = _R*X + _T;
- Vector2d p;
- p[0] = XX[0] / XX[2];
- p[1] = XX[1] / XX[2];
- p = distortion(p);
-
- Vector2d res;
- res[0] = _K[0][0] * p[0] + _K[0][1] * p[1] + _K[0][2];
- res[1] = _K[1][1] * p[1] + _K[1][2];
- return res;
- }
-
- Vector3d unprojectPixel(Vector2d const &p, double depth = 1) const
- {
- Vector3d pp;
- pp[0] = p[0]; pp[1] = p[1]; pp[2] = 1.0;
- Vector3d ray = _invK * pp;
- ray[0] *= depth/ray[2];
- ray[1] *= depth/ray[2];
- ray[2] = depth;
- ray = _Rt * ray;
- return _center + ray;
- }
-
- Vector3d transformPointIntoCameraSpace(Vector3d const& p) const
- {
- return _R*p + _T;
- }
-
- Vector3d transformPointFromCameraSpace(Vector3d const& p) const
- {
- return _Rt*(p-_T);
- }
-
- Vector3d transformDirectionFromCameraSpace(Vector3d const& dir) const
- {
- return _Rt*dir;
- }
-
- Vector3d const& cameraCenter() const
- {
- return _center;
- }
-
- Vector3d opticalAxis() const
- {
- return this->transformDirectionFromCameraSpace(makeVector3(0.0, 0.0, 1.0));
- }
-
- Vector3d upVector() const
- {
- return this->transformDirectionFromCameraSpace(makeVector3(0.0, 1.0, 0.0));
- }
-
- Vector3d rightVector() const
- {
- return this->transformDirectionFromCameraSpace(makeVector3(1.0, 0.0, 0.0));
- }
-
- Vector3d getRay(Vector2d const& p) const
- {
- Vector3d pp = makeVector3(p[0], p[1], 1.0);
- Vector3d ray = _invK * pp;
- ray = _Rt * ray;
- normalizeVector(ray);
- return ray;
- }
-
- protected:
- void updateCachedValues(bool intrinsic, bool orientation)
- {
- if (intrinsic) _invK = invertedMatrix(_K);
-
- if (orientation)
- {
- makeTransposedMatrix(_R, _Rt);
- _center = _Rt * (-1.0 * _T);
- }
- }
-
- Matrix3x3d _K, _R;
- Vector3d _T;
- Matrix3x3d _invK, _Rt;
- Vector3d _center;
- }; // end struct CameraMatrix
-
-} // end namespace V3D
-
-#endif
diff --git a/extern/libmv/third_party/ssba/Geometry/v3d_distortion.h b/extern/libmv/third_party/ssba/Geometry/v3d_distortion.h
deleted file mode 100644
index d0816558314..00000000000
--- a/extern/libmv/third_party/ssba/Geometry/v3d_distortion.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// -*- C++ -*-
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA 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.
-
-SSBA is distributed in the hope that 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 SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef V3D_DISTORTION_H
-#define V3D_DISTORTION_H
-
-#include "Math/v3d_linear.h"
-#include "Math/v3d_linear_utils.h"
-
-namespace V3D
-{
-
- struct StdDistortionFunction
- {
- double k1, k2, p1, p2;
-
- StdDistortionFunction()
- : k1(0), k2(0), p1(0), p2(0)
- { }
-
- Vector2d operator()(Vector2d const& xu) const
- {
- double const r2 = xu[0]*xu[0] + xu[1]*xu[1];
- double const r4 = r2*r2;
- double const kr = 1 + k1*r2 + k2*r4;
-
- Vector2d xd;
- xd[0] = kr * xu[0] + 2*p1*xu[0]*xu[1] + p2*(r2 + 2*xu[0]*xu[0]);
- xd[1] = kr * xu[1] + 2*p2*xu[0]*xu[1] + p1*(r2 + 2*xu[1]*xu[1]);
- return xd;
- }
-
- Matrix2x2d derivativeWrtRadialParameters(Vector2d const& xu) const
- {
- double const r2 = xu[0]*xu[0] + xu[1]*xu[1];
- double const r4 = r2*r2;
- //double const kr = 1 + k1*r2 + k2*r4;
-
- Matrix2x2d deriv;
-
- deriv[0][0] = xu[0] * r2; // d xd/d k1
- deriv[0][1] = xu[0] * r4; // d xd/d k2
- deriv[1][0] = xu[1] * r2; // d yd/d k1
- deriv[1][1] = xu[1] * r4; // d yd/d k2
- return deriv;
- }
-
- Matrix2x2d derivativeWrtTangentialParameters(Vector2d const& xu) const
- {
- double const r2 = xu[0]*xu[0] + xu[1]*xu[1];
- //double const r4 = r2*r2;
- //double const kr = 1 + k1*r2 + k2*r4;
-
- Matrix2x2d deriv;
- deriv[0][0] = 2*xu[0]*xu[1]; // d xd/d p1
- deriv[0][1] = r2 + 2*xu[0]*xu[0]; // d xd/d p2
- deriv[1][0] = r2 + 2*xu[1]*xu[1]; // d yd/d p1
- deriv[1][1] = deriv[0][0]; // d yd/d p2
- return deriv;
- }
-
- Matrix2x2d derivativeWrtUndistortedPoint(Vector2d const& xu) const
- {
- double const r2 = xu[0]*xu[0] + xu[1]*xu[1];
- double const r4 = r2*r2;
- double const kr = 1 + k1*r2 + k2*r4;
- double const dkr = 2*k1 + 4*k2*r2;
-
- Matrix2x2d deriv;
- deriv[0][0] = kr + xu[0] * xu[0] * dkr + 2*p1*xu[1] + 6*p2*xu[0]; // d xd/d xu
- deriv[0][1] = xu[0] * xu[1] * dkr + 2*p1*xu[0] + 2*p2*xu[1]; // d xd/d yu
- deriv[1][0] = deriv[0][1]; // d yd/d xu
- deriv[1][1] = kr + xu[1] * xu[1] * dkr + 6*p1*xu[1] + 2*p2*xu[0]; // d yd/d yu
- return deriv;
- }
- }; // end struct StdDistortionFunction
-
-} // end namespace V3D
-
-#endif
diff --git a/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp b/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp
deleted file mode 100644
index 7eb2dfac5d9..00000000000
--- a/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.cpp
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA 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.
-
-SSBA is distributed in the hope that 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 SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "Geometry/v3d_metricbundle.h"
-
-#if defined(V3DLIB_ENABLE_SUITESPARSE)
-
-namespace
-{
-
- typedef V3D::InlineMatrix<double, 2, 4> Matrix2x4d;
- typedef V3D::InlineMatrix<double, 4, 2> Matrix4x2d;
- typedef V3D::InlineMatrix<double, 2, 6> Matrix2x6d;
-
-} // end namespace <>
-
-namespace V3D
-{
-
- void
- MetricBundleOptimizerBase::updateParametersA(VectorArray<double> const& deltaAi)
- {
- Vector3d T, omega;
- Matrix3x3d R0, dR;
-
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- {
- T = _cams[i].getTranslation();
- T[0] += deltaAi[i][0];
- T[1] += deltaAi[i][1];
- T[2] += deltaAi[i][2];
- _cams[i].setTranslation(T);
-
- // Create incremental rotation using Rodriguez formula.
- R0 = _cams[i].getRotation();
- omega[0] = deltaAi[i][3];
- omega[1] = deltaAi[i][4];
- omega[2] = deltaAi[i][5];
- createRotationMatrixRodriguez(omega, dR);
- _cams[i].setRotation(dR * R0);
- } // end for (i)
- } // end MetricBundleOptimizerBase::updateParametersA()
-
- void
- MetricBundleOptimizerBase::updateParametersB(VectorArray<double> const& deltaBj)
- {
- for (int j = _nNonvaryingB; j < _nParametersB; ++j)
- {
- _Xs[j][0] += deltaBj[j][0];
- _Xs[j][1] += deltaBj[j][1];
- _Xs[j][2] += deltaBj[j][2];
- }
- } // end MetricBundleOptimizerBase::updateParametersB()
-
- void
- MetricBundleOptimizerBase::poseDerivatives(int i, int j, Vector3d& XX,
- Matrix3x6d& d_dRT, Matrix3x3d& d_dX) const
- {
- XX = _cams[i].transformPointIntoCameraSpace(_Xs[j]);
-
- // See Frank Dellaerts bundle adjustment tutorial.
- // d(dR * R0 * X + t)/d omega = -[R0 * X]_x
- Matrix3x3d J;
- makeCrossProductMatrix(XX - _cams[i].getTranslation(), J);
- scaleMatrixIP(-1.0, J);
-
- // Now the transformation from world coords into camera space is xx = Rx + T
- // Hence the derivative of x wrt. T is just the identity matrix.
- makeIdentityMatrix(d_dRT);
- copyMatrixSlice(J, 0, 0, 3, 3, d_dRT, 0, 3);
-
- // The derivative of Rx+T wrt x is just R.
- copyMatrix(_cams[i].getRotation(), d_dX);
- } // end MetricBundleOptimizerBase::poseDerivatives()
-
-
-//----------------------------------------------------------------------
-
- void
- StdMetricBundleOptimizer::fillJacobians(Matrix<double>& Ak,
- Matrix<double>& Bk,
- Matrix<double>& Ck,
- int i, int j, int k)
- {
- Vector3d XX;
- Matrix3x6d d_dRT;
- Matrix3x3d d_dX;
- this->poseDerivatives(i, j, XX, d_dRT, d_dX);
-
- double const f = _cams[i].getFocalLength();
- double const ar = _cams[i].getAspectRatio();
-
- Matrix2x3d dp_dX;
- double const bx = f / (XX[2] * XX[2]);
- double const by = ar * bx;
- dp_dX[0][0] = bx * XX[2]; dp_dX[0][1] = 0; dp_dX[0][2] = -bx * XX[0];
- dp_dX[1][0] = 0; dp_dX[1][1] = by * XX[2]; dp_dX[1][2] = -by * XX[1];
-
- multiply_A_B(dp_dX, d_dRT, Ak);
- multiply_A_B(dp_dX, d_dX, Bk);
- } // end StdMetricBundleOptimizer::fillJacobians()
-
- //----------------------------------------------------------------------
-
- void
- CommonInternalsMetricBundleOptimizer::fillJacobians(Matrix<double>& Ak,
- Matrix<double>& Bk,
- Matrix<double>& Ck,
- int i, int j, int k)
- {
- double const focalLength = _K[0][0];
-
- Vector3d XX;
- Matrix3x6d dXX_dRT;
- Matrix3x3d dXX_dX;
- this->poseDerivatives(i, j, XX, dXX_dRT, dXX_dX);
-
- Vector2d xu; // undistorted image point
- xu[0] = XX[0] / XX[2];
- xu[1] = XX[1] / XX[2];
-
- Vector2d const xd = _distortion(xu); // distorted image point
-
- Matrix2x2d dp_dxd;
- dp_dxd[0][0] = focalLength; dp_dxd[0][1] = 0;
- dp_dxd[1][0] = 0; dp_dxd[1][1] = _cachedAspectRatio * focalLength;
-
- {
- // First, lets do the derivative wrt the structure and motion parameters.
- Matrix2x3d dxu_dXX;
- dxu_dXX[0][0] = 1.0f / XX[2]; dxu_dXX[0][1] = 0; dxu_dXX[0][2] = -XX[0]/(XX[2]*XX[2]);
- dxu_dXX[1][0] = 0; dxu_dXX[1][1] = 1.0f / XX[2]; dxu_dXX[1][2] = -XX[1]/(XX[2]*XX[2]);
-
- Matrix2x2d dxd_dxu = _distortion.derivativeWrtUndistortedPoint(xu);
-
- Matrix2x2d dp_dxu = dp_dxd * dxd_dxu;
- Matrix2x3d dp_dXX = dp_dxu * dxu_dXX;
-
- multiply_A_B(dp_dXX, dXX_dRT, Ak);
- multiply_A_B(dp_dXX, dXX_dX, Bk);
- } // end scope
-
- switch (_mode)
- {
- case FULL_BUNDLE_FOCAL_AND_RADIAL_K1:
- {
- // Focal length.
- Ck[0][0] = xd[0];
- Ck[1][0] = xd[1];
-
- // For radial, k1 only.
- Matrix2x2d dxd_dk1k2 = _distortion.derivativeWrtRadialParameters(xu);
- Matrix2x2d d_dk1k2 = dp_dxd * dxd_dk1k2;
- Ck[0][1] = d_dk1k2[0][0];
- Ck[1][1] = d_dk1k2[1][0];
- break;
- }
- case FULL_BUNDLE_FOCAL_AND_RADIAL:
- {
- // Focal length.
- Ck[0][0] = xd[0];
- Ck[1][0] = xd[1];
-
- // Radial k1 and k2.
- Matrix2x2d dxd_dk1k2 = _distortion.derivativeWrtRadialParameters(xu);
- Matrix2x2d d_dk1k2 = dp_dxd * dxd_dk1k2;
- copyMatrixSlice(d_dk1k2, 0, 0, 2, 2, Ck, 0, 1);
- break;
- }
- case FULL_BUNDLE_RADIAL_TANGENTIAL:
- {
- Matrix2x2d dxd_dp1p2 = _distortion.derivativeWrtTangentialParameters(xu);
- Matrix2x2d d_dp1p2 = dp_dxd * dxd_dp1p2;
- copyMatrixSlice(d_dp1p2, 0, 0, 2, 2, Ck, 0, 5);
- // No break here!
- }
- case FULL_BUNDLE_RADIAL:
- {
- Matrix2x2d dxd_dk1k2 = _distortion.derivativeWrtRadialParameters(xu);
- Matrix2x2d d_dk1k2 = dp_dxd * dxd_dk1k2;
- copyMatrixSlice(d_dk1k2, 0, 0, 2, 2, Ck, 0, 3);
- // No break here!
- }
- case FULL_BUNDLE_FOCAL_LENGTH_PP:
- {
- Ck[0][1] = 1; Ck[0][2] = 0;
- Ck[1][1] = 0; Ck[1][2] = 1;
- // No break here!
- }
- case FULL_BUNDLE_FOCAL_LENGTH:
- {
- Ck[0][0] = xd[0];
- Ck[1][0] = xd[1];
- }
- case FULL_BUNDLE_METRIC:
- {
- }
- } // end switch
- } // end CommonInternalsMetricBundleOptimizer::fillJacobians()
-
- void
- CommonInternalsMetricBundleOptimizer::updateParametersC(Vector<double> const& deltaC)
- {
- switch (_mode)
- {
- case FULL_BUNDLE_FOCAL_AND_RADIAL_K1:
- {
- _K[0][0] += deltaC[0];
- _K[1][1] = _cachedAspectRatio * _K[0][0];
- _distortion.k1 += deltaC[1];
- break;
- }
- case FULL_BUNDLE_FOCAL_AND_RADIAL:
- {
- _K[0][0] += deltaC[0];
- _K[1][1] = _cachedAspectRatio * _K[0][0];
- _distortion.k1 += deltaC[1];
- _distortion.k2 += deltaC[2];
- break;
- }
- case FULL_BUNDLE_RADIAL_TANGENTIAL:
- {
- _distortion.p1 += deltaC[5];
- _distortion.p2 += deltaC[6];
- // No break here!
- }
- case FULL_BUNDLE_RADIAL:
- {
- _distortion.k1 += deltaC[3];
- _distortion.k2 += deltaC[4];
- // No break here!
- }
- case FULL_BUNDLE_FOCAL_LENGTH_PP:
- {
- _K[0][2] += deltaC[1];
- _K[1][2] += deltaC[2];
- // No break here!
- }
- case FULL_BUNDLE_FOCAL_LENGTH:
- {
- _K[0][0] += deltaC[0];
- _K[1][1] = _cachedAspectRatio * _K[0][0];
- }
- case FULL_BUNDLE_METRIC:
- {
- }
- } // end switch
- } // end CommonInternalsMetricBundleOptimizer::updateParametersC()
-
- //----------------------------------------------------------------------
-
- void
- VaryingInternalsMetricBundleOptimizer::fillJacobians(Matrix<double>& Ak,
- Matrix<double>& Bk,
- Matrix<double>& Ck,
- int i, int j, int k)
- {
- Vector3d XX;
- Matrix3x6d dXX_dRT;
- Matrix3x3d dXX_dX;
- this->poseDerivatives(i, j, XX, dXX_dRT, dXX_dX);
-
- Vector2d xu; // undistorted image point
- xu[0] = XX[0] / XX[2];
- xu[1] = XX[1] / XX[2];
-
- Vector2d const xd = _distortions[i](xu); // distorted image point
-
- double const focalLength = _cams[i].getFocalLength();
- double const aspectRatio = _cams[i].getAspectRatio();
-
- Matrix2x2d dp_dxd;
- dp_dxd[0][0] = focalLength; dp_dxd[0][1] = 0;
- dp_dxd[1][0] = 0; dp_dxd[1][1] = aspectRatio * focalLength;
-
- {
- // First, lets do the derivative wrt the structure and motion parameters.
- Matrix2x3d dxu_dXX;
- dxu_dXX[0][0] = 1.0f / XX[2]; dxu_dXX[0][1] = 0; dxu_dXX[0][2] = -XX[0]/(XX[2]*XX[2]);
- dxu_dXX[1][0] = 0; dxu_dXX[1][1] = 1.0f / XX[2]; dxu_dXX[1][2] = -XX[1]/(XX[2]*XX[2]);
-
- Matrix2x2d dxd_dxu = _distortions[i].derivativeWrtUndistortedPoint(xu);
-
- Matrix2x2d dp_dxu = dp_dxd * dxd_dxu;
- Matrix2x3d dp_dXX = dp_dxu * dxu_dXX;
-
- Matrix2x6d dp_dRT;
-
- multiply_A_B(dp_dXX, dXX_dRT, dp_dRT);
- copyMatrixSlice(dp_dRT, 0, 0, 2, 6, Ak, 0, 0);
- multiply_A_B(dp_dXX, dXX_dX, Bk);
- } // end scope
-
- switch (_mode)
- {
- case FULL_BUNDLE_RADIAL_TANGENTIAL:
- {
- Matrix2x2d dxd_dp1p2 = _distortions[i].derivativeWrtTangentialParameters(xu);
- Matrix2x2d d_dp1p2 = dp_dxd * dxd_dp1p2;
- copyMatrixSlice(d_dp1p2, 0, 0, 2, 2, Ak, 0, 11);
- // No break here!
- }
- case FULL_BUNDLE_RADIAL:
- {
- Matrix2x2d dxd_dk1k2 = _distortions[i].derivativeWrtRadialParameters(xu);
- Matrix2x2d d_dk1k2 = dp_dxd * dxd_dk1k2;
- copyMatrixSlice(d_dk1k2, 0, 0, 2, 2, Ak, 0, 9);
- // No break here!
- }
- case FULL_BUNDLE_FOCAL_LENGTH_PP:
- {
- Ak[0][7] = 1; Ak[0][8] = 0;
- Ak[1][7] = 0; Ak[1][8] = 1;
- // No break here!
- }
- case FULL_BUNDLE_FOCAL_LENGTH:
- {
- Ak[0][6] = xd[0];
- Ak[1][6] = xd[1];
- }
- case FULL_BUNDLE_METRIC:
- {
- }
- } // end switch
- } // end VaryingInternalsMetricBundleOptimizer::fillJacobians()
-
- void
- VaryingInternalsMetricBundleOptimizer::updateParametersA(VectorArray<double> const& deltaAi)
- {
- Vector3d T, omega;
- Matrix3x3d R0, dR, K;
-
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- {
- Vector<double> const& deltaA = deltaAi[i];
-
- T = _cams[i].getTranslation();
- T[0] += deltaA[0];
- T[1] += deltaA[1];
- T[2] += deltaA[2];
- _cams[i].setTranslation(T);
-
- // Create incremental rotation using Rodriguez formula.
- R0 = _cams[i].getRotation();
- omega[0] = deltaA[3];
- omega[1] = deltaA[4];
- omega[2] = deltaA[5];
- createRotationMatrixRodriguez(omega, dR);
- _cams[i].setRotation(dR * R0);
-
- K = _cams[i].getIntrinsic();
-
- switch (_mode)
- {
- case FULL_BUNDLE_RADIAL_TANGENTIAL:
- {
- _distortions[i].p1 += deltaA[11];
- _distortions[i].p2 += deltaA[12];
- // No break here!
- }
- case FULL_BUNDLE_RADIAL:
- {
- _distortions[i].k1 += deltaA[9];
- _distortions[i].k2 += deltaA[10];
- // No break here!
- }
- case FULL_BUNDLE_FOCAL_LENGTH_PP:
- {
- K[0][2] += deltaA[7];
- K[1][2] += deltaA[8];
- // No break here!
- }
- case FULL_BUNDLE_FOCAL_LENGTH:
- {
- double const ar = K[1][1] / K[0][0];
- K[0][0] += deltaA[6];
- K[1][1] = ar * K[0][0];
- }
- case FULL_BUNDLE_METRIC:
- {
- }
- } // end switch
- _cams[i].setIntrinsic(K);
- } // end for (i)
- } // end VaryingInternalsMetricBundleOptimizer::updateParametersC()
-
-} // end namespace V3D
-
-#endif // defined(V3DLIB_ENABLE_SUITESPARSE)
diff --git a/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h b/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h
deleted file mode 100644
index 339e174ed9e..00000000000
--- a/extern/libmv/third_party/ssba/Geometry/v3d_metricbundle.h
+++ /dev/null
@@ -1,352 +0,0 @@
-// -*- C++ -*-
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA 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.
-
-SSBA is distributed in the hope that 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 SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef V3D_METRICBUNDLE_H
-#define V3D_METRICBUNDLE_H
-
-# if defined(V3DLIB_ENABLE_SUITESPARSE)
-
-#include "Math/v3d_optimization.h"
-#include "Math/v3d_linear.h"
-#include "Math/v3d_linear_utils.h"
-#include "Geometry/v3d_cameramatrix.h"
-#include "Geometry/v3d_distortion.h"
-
-namespace V3D
-{
-
- // This structure provides some helper functions common to all metric BAs
- struct MetricBundleOptimizerBase : public SparseLevenbergOptimizer
- {
- typedef SparseLevenbergOptimizer Base;
-
- MetricBundleOptimizerBase(double inlierThreshold,
- vector<CameraMatrix>& cams,
- vector<Vector3d >& Xs,
- vector<Vector2d > const& measurements,
- vector<int> const& corrspondingView,
- vector<int> const& corrspondingPoint,
- int nAddParamsA, int nParamsC)
- : SparseLevenbergOptimizer(2, cams.size(), 6+nAddParamsA, Xs.size(), 3, nParamsC,
- corrspondingView, corrspondingPoint),
- _cams(cams), _Xs(Xs), _measurements(measurements),
- _savedTranslations(cams.size()), _savedRotations(cams.size()),
- _savedXs(Xs.size()),
- _inlierThreshold(inlierThreshold), _cachedParamLength(0.0)
- {
- // Since we assume that BA does not alter the inputs too much,
- // we compute the overall length of the parameter vector in advance
- // and return that value as the result of getParameterLength().
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- {
- _cachedParamLength += sqrNorm_L2(_cams[i].getTranslation());
- _cachedParamLength += 3.0; // Assume eye(3) for R.
- }
- for (int j = _nNonvaryingB; j < _nParametersB; ++j)
- _cachedParamLength += sqrNorm_L2(_Xs[j]);
-
- _cachedParamLength = sqrt(_cachedParamLength);
- }
-
- // Huber robust cost function.
- virtual void fillWeights(VectorArray<double> const& residual, Vector<double>& w)
- {
- for (unsigned int k = 0; k < w.size(); ++k)
- {
- Vector<double> const& r = residual[k];
- double const e = norm_L2(r);
- w[k] = (e < _inlierThreshold) ? 1.0 : sqrt(_inlierThreshold / e);
- } // end for (k)
- }
-
- virtual double getParameterLength() const
- {
- return _cachedParamLength;
- }
-
- virtual void updateParametersA(VectorArray<double> const& deltaAi);
- virtual void updateParametersB(VectorArray<double> const& deltaBj);
- virtual void updateParametersC(Vector<double> const& deltaC)
- {
- (void)deltaC;
- }
-
- virtual void saveAllParameters()
- {
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- {
- _savedTranslations[i] = _cams[i].getTranslation();
- _savedRotations[i] = _cams[i].getRotation();
- }
- _savedXs = _Xs;
- }
-
- virtual void restoreAllParameters()
- {
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- {
- _cams[i].setTranslation(_savedTranslations[i]);
- _cams[i].setRotation(_savedRotations[i]);
- }
- _Xs = _savedXs;
- }
-
- protected:
- typedef InlineMatrix<double, 3, 6> Matrix3x6d;
-
- void poseDerivatives(int i, int j, Vector3d& XX,
- Matrix3x6d& d_dRT, Matrix3x3d& d_dX) const;
-
- vector<CameraMatrix>& _cams;
- vector<Vector3d>& _Xs;
-
- vector<Vector2d> const& _measurements;
-
- vector<Vector3d> _savedTranslations;
- vector<Matrix3x3d> _savedRotations;
- vector<Vector3d> _savedXs;
-
- double const _inlierThreshold;
- double _cachedParamLength;
- }; // end struct MetricBundleOptimizerBase
-
- struct StdMetricBundleOptimizer : public MetricBundleOptimizerBase
- {
- typedef MetricBundleOptimizerBase Base;
-
- StdMetricBundleOptimizer(double inlierThreshold,
- vector<CameraMatrix>& cams,
- vector<Vector3d >& Xs,
- vector<Vector2d > const& measurements,
- vector<int> const& corrspondingView,
- vector<int> const& corrspondingPoint)
- : MetricBundleOptimizerBase(inlierThreshold, cams, Xs, measurements,
- corrspondingView, corrspondingPoint, 0, 0)
- { }
-
- virtual void evalResidual(VectorArray<double>& e)
- {
- for (unsigned int k = 0; k < e.count(); ++k)
- {
- int const i = _correspondingParamA[k];
- int const j = _correspondingParamB[k];
-
- Vector2d const q = _cams[i].projectPoint(_Xs[j]);
- e[k][0] = q[0] - _measurements[k][0];
- e[k][1] = q[1] - _measurements[k][1];
- }
- }
-
- virtual void fillJacobians(Matrix<double>& Ak, Matrix<double>& Bk, Matrix<double>& Ck,
- int i, int j, int k);
- }; // end struct StdMetricBundleOptimizer
-
-//----------------------------------------------------------------------
-
- enum
- {
- FULL_BUNDLE_METRIC = 0,
- FULL_BUNDLE_FOCAL_LENGTH = 1, // f
- FULL_BUNDLE_FOCAL_LENGTH_PP = 2, // f, cx, cy
- FULL_BUNDLE_RADIAL = 3, // f, cx, cy, k1, k2
- FULL_BUNDLE_RADIAL_TANGENTIAL = 4, // f, cx, cy, k1, k2, p1, p2
- FULL_BUNDLE_FOCAL_AND_RADIAL_K1 = 5, // f, k1
- FULL_BUNDLE_FOCAL_AND_RADIAL = 6, // f, k1, k2
- };
-
- struct CommonInternalsMetricBundleOptimizer : public MetricBundleOptimizerBase
- {
- static int globalParamDimensionFromMode(int mode)
- {
- switch (mode)
- {
- case FULL_BUNDLE_METRIC: return 0;
- case FULL_BUNDLE_FOCAL_LENGTH: return 1;
- case FULL_BUNDLE_FOCAL_LENGTH_PP: return 3;
- case FULL_BUNDLE_RADIAL: return 5;
- case FULL_BUNDLE_RADIAL_TANGENTIAL: return 7;
- case FULL_BUNDLE_FOCAL_AND_RADIAL_K1: return 2;
- case FULL_BUNDLE_FOCAL_AND_RADIAL: return 3;
- }
- return 0;
- }
-
- typedef MetricBundleOptimizerBase Base;
-
- CommonInternalsMetricBundleOptimizer(int mode,
- double inlierThreshold,
- Matrix3x3d& K,
- StdDistortionFunction& distortion,
- vector<CameraMatrix>& cams,
- vector<Vector3d >& Xs,
- vector<Vector2d > const& measurements,
- vector<int> const& corrspondingView,
- vector<int> const& corrspondingPoint)
- : MetricBundleOptimizerBase(inlierThreshold, cams, Xs, measurements,
- corrspondingView, corrspondingPoint,
- 0, globalParamDimensionFromMode(mode)),
- _mode(mode), _K(K), _distortion(distortion)
- {
- _cachedAspectRatio = K[1][1] / K[0][0];
- }
-
- Vector2d projectPoint(Vector3d const& X, int i) const
- {
- Vector3d const XX = _cams[i].transformPointIntoCameraSpace(X);
- Vector2d p;
- p[0] = XX[0] / XX[2];
- p[1] = XX[1] / XX[2];
- p = _distortion(p);
- Vector2d res;
- res[0] = _K[0][0] * p[0] + _K[0][1] * p[1] + _K[0][2];
- res[1] = _K[1][1] * p[1] + _K[1][2];
- return res;
- }
-
- virtual void evalResidual(VectorArray<double>& e)
- {
- for (unsigned int k = 0; k < e.count(); ++k)
- {
- int const i = _correspondingParamA[k];
- int const j = _correspondingParamB[k];
-
- Vector2d const q = this->projectPoint(_Xs[j], i);
- e[k][0] = q[0] - _measurements[k][0];
- e[k][1] = q[1] - _measurements[k][1];
- }
- }
-
- virtual void fillJacobians(Matrix<double>& Ak, Matrix<double>& Bk, Matrix<double>& Ck,
- int i, int j, int k);
-
- virtual void updateParametersC(Vector<double> const& deltaC);
-
- virtual void saveAllParameters()
- {
- Base::saveAllParameters();
- _savedK = _K;
- _savedDistortion = _distortion;
- }
-
- virtual void restoreAllParameters()
- {
- Base::restoreAllParameters();
- _K = _savedK;
- _distortion = _savedDistortion;
- }
-
- protected:
- int _mode;
- Matrix3x3d& _K;
- StdDistortionFunction& _distortion;
-
- Matrix3x3d _savedK;
- StdDistortionFunction _savedDistortion;
- double _cachedAspectRatio;
- }; // end struct CommonInternalsMetricBundleOptimizer
-
-//----------------------------------------------------------------------
-
- struct VaryingInternalsMetricBundleOptimizer : public MetricBundleOptimizerBase
- {
- static int extParamDimensionFromMode(int mode)
- {
- switch (mode)
- {
- case FULL_BUNDLE_METRIC: return 0;
- case FULL_BUNDLE_FOCAL_LENGTH: return 1;
- case FULL_BUNDLE_FOCAL_LENGTH_PP: return 3;
- case FULL_BUNDLE_RADIAL: return 5;
- case FULL_BUNDLE_RADIAL_TANGENTIAL: return 7;
- case FULL_BUNDLE_FOCAL_AND_RADIAL_K1: return 2;
- case FULL_BUNDLE_FOCAL_AND_RADIAL: return 3;
- }
- return 0;
- }
-
- typedef MetricBundleOptimizerBase Base;
-
- VaryingInternalsMetricBundleOptimizer(int mode,
- double inlierThreshold,
- std::vector<StdDistortionFunction>& distortions,
- vector<CameraMatrix>& cams,
- vector<Vector3d >& Xs,
- vector<Vector2d > const& measurements,
- vector<int> const& corrspondingView,
- vector<int> const& corrspondingPoint)
- : MetricBundleOptimizerBase(inlierThreshold, cams, Xs, measurements,
- corrspondingView, corrspondingPoint,
- extParamDimensionFromMode(mode), 0),
- _mode(mode), _distortions(distortions),
- _savedKs(cams.size()), _savedDistortions(cams.size())
- { }
-
- Vector2d projectPoint(Vector3d const& X, int i) const
- {
- return _cams[i].projectPoint(_distortions[i], X);
- }
-
- virtual void evalResidual(VectorArray<double>& e)
- {
- for (unsigned int k = 0; k < e.count(); ++k)
- {
- int const i = _correspondingParamA[k];
- int const j = _correspondingParamB[k];
-
- Vector2d const q = this->projectPoint(_Xs[j], i);
- e[k][0] = q[0] - _measurements[k][0];
- e[k][1] = q[1] - _measurements[k][1];
- }
- }
-
- virtual void fillJacobians(Matrix<double>& Ak, Matrix<double>& Bk, Matrix<double>& Ck,
- int i, int j, int k);
-
- virtual void updateParametersA(VectorArray<double> const& deltaAi);
-
- virtual void saveAllParameters()
- {
- Base::saveAllParameters();
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- _savedKs[i] = _cams[i].getIntrinsic();
- std::copy(_distortions.begin(), _distortions.end(), _savedDistortions.begin());
- }
-
- virtual void restoreAllParameters()
- {
- Base::restoreAllParameters();
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- _cams[i].setIntrinsic(_savedKs[i]);
- std::copy(_savedDistortions.begin(), _savedDistortions.end(), _distortions.begin());
- }
-
- protected:
- int _mode;
- std::vector<StdDistortionFunction>& _distortions;
-
- std::vector<Matrix3x3d> _savedKs;
- std::vector<StdDistortionFunction> _savedDistortions;
- }; // end struct VaryingInternalsMetricBundleOptimizer
-
-} // end namespace V3D
-
-# endif
-
-#endif
diff --git a/extern/libmv/third_party/ssba/Math/v3d_linear.h b/extern/libmv/third_party/ssba/Math/v3d_linear.h
deleted file mode 100644
index 7d6e898169c..00000000000
--- a/extern/libmv/third_party/ssba/Math/v3d_linear.h
+++ /dev/null
@@ -1,923 +0,0 @@
-// -*- C++ -*-
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA 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.
-
-SSBA is distributed in the hope that 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 SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef V3D_LINEAR_H
-#define V3D_LINEAR_H
-
-#include <cassert>
-#include <algorithm>
-#include <vector>
-#include <cmath>
-
-namespace V3D
-{
- using namespace std;
-
- //! Unboxed vector type
- template <typename Elem, int Size>
- struct InlineVectorBase
- {
- typedef Elem value_type;
- typedef Elem element_type;
-
- typedef Elem const * const_iterator;
- typedef Elem * iterator;
-
- static unsigned int size() { return Size; }
-
- Elem& operator[](unsigned int i) { return _vec[i]; }
- Elem operator[](unsigned int i) const { return _vec[i]; }
-
- Elem& operator()(unsigned int i) { return _vec[i-1]; }
- Elem operator()(unsigned int i) const { return _vec[i-1]; }
-
- const_iterator begin() const { return _vec; }
- iterator begin() { return _vec; }
- const_iterator end() const { return _vec + Size; }
- iterator end() { return _vec + Size; }
-
- void newsize(unsigned int sz) const
- {
- assert(sz == Size);
- }
-
- protected:
- Elem _vec[Size];
- };
-
- //! Boxed (heap allocated) vector.
- template <typename Elem>
- struct VectorBase
- {
- typedef Elem value_type;
- typedef Elem element_type;
-
- typedef Elem const * const_iterator;
- typedef Elem * iterator;
-
- VectorBase()
- : _size(0), _ownsVec(true), _vec(0)
- { }
-
- VectorBase(unsigned int size)
- : _size(size), _ownsVec(true), _vec(0)
- {
- if (size > 0) _vec = new Elem[size];
- }
-
- VectorBase(unsigned int size, Elem * values)
- : _size(size), _ownsVec(false), _vec(values)
- { }
-
- VectorBase(VectorBase<Elem> const& a)
- : _size(0), _ownsVec(true), _vec(0)
- {
- _size = a._size;
- if (_size == 0) return;
- _vec = new Elem[_size];
- std::copy(a._vec, a._vec + _size, _vec);
- }
-
- ~VectorBase() { if (_ownsVec && _vec != 0) delete [] _vec; }
-
- VectorBase& operator=(VectorBase<Elem> const& a)
- {
- if (this == &a) return *this;
-
- this->newsize(a._size);
- std::copy(a._vec, a._vec + _size, _vec);
- return *this;
- }
-
- unsigned int size() const { return _size; }
-
- VectorBase<Elem>& newsize(unsigned int sz)
- {
- if (sz == _size) return *this;
- assert(_ownsVec);
-
- __destroy();
- _size = sz;
- if (_size > 0) _vec = new Elem[_size];
-
- return *this;
- }
-
-
- Elem& operator[](unsigned int i) { return _vec[i]; }
- Elem operator[](unsigned int i) const { return _vec[i]; }
-
- Elem& operator()(unsigned int i) { return _vec[i-1]; }
- Elem operator()(unsigned int i) const { return _vec[i-1]; }
-
- const_iterator begin() const { return _vec; }
- iterator begin() { return _vec; }
- const_iterator end() const { return _vec + _size; }
- iterator end() { return _vec + _size; }
-
- protected:
- void __destroy()
- {
- assert(_ownsVec);
-
- if (_vec != 0) delete [] _vec;
- _size = 0;
- _vec = 0;
- }
-
- unsigned int _size;
- bool _ownsVec;
- Elem * _vec;
- };
-
- template <typename Elem, int Rows, int Cols>
- struct InlineMatrixBase
- {
- typedef Elem value_type;
- typedef Elem element_type;
-
- typedef Elem * iterator;
- typedef Elem const * const_iterator;
-
- static unsigned int num_rows() { return Rows; }
- static unsigned int num_cols() { return Cols; }
-
- Elem * operator[](unsigned int row) { return _m[row]; }
- Elem const * operator[](unsigned int row) const { return _m[row]; }
-
- Elem& operator()(unsigned int row, unsigned int col) { return _m[row-1][col-1]; }
- Elem operator()(unsigned int row, unsigned int col) const { return _m[row-1][col-1]; }
-
- template <typename Vec>
- void getRowSlice(unsigned int row, unsigned int first, unsigned int last, Vec& dst) const
- {
- for (unsigned int c = first; c < last; ++c) dst[c-first] = _m[row][c];
- }
-
- template <typename Vec>
- void getColumnSlice(unsigned int first, unsigned int len, unsigned int col, Vec& dst) const
- {
- for (unsigned int r = 0; r < len; ++r) dst[r] = _m[r+first][col];
- }
-
- void newsize(unsigned int rows, unsigned int cols) const
- {
- assert(rows == Rows && cols == Cols);
- }
-
- const_iterator begin() const { return &_m[0][0]; }
- iterator begin() { return &_m[0][0]; }
- const_iterator end() const { return &_m[0][0] + Rows*Cols; }
- iterator end() { return &_m[0][0] + Rows*Cols; }
-
- protected:
- Elem _m[Rows][Cols];
- };
-
- template <typename Elem>
- struct MatrixBase
- {
- typedef Elem value_type;
- typedef Elem element_type;
-
- typedef Elem const * const_iterator;
- typedef Elem * iterator;
-
- MatrixBase()
- : _rows(0), _cols(0), _ownsData(true), _m(0)
- { }
-
- MatrixBase(unsigned int rows, unsigned int cols)
- : _rows(rows), _cols(cols), _ownsData(true), _m(0)
- {
- if (_rows * _cols == 0) return;
- _m = new Elem[rows*cols];
- }
-
- MatrixBase(unsigned int rows, unsigned int cols, Elem * values)
- : _rows(rows), _cols(cols), _ownsData(false), _m(values)
- { }
-
- MatrixBase(MatrixBase<Elem> const& a)
- : _ownsData(true), _m(0)
- {
- _rows = a._rows; _cols = a._cols;
- if (_rows * _cols == 0) return;
- _m = new Elem[_rows*_cols];
- std::copy(a._m, a._m+_rows*_cols, _m);
- }
-
- ~MatrixBase()
- {
- if (_ownsData && _m != 0) delete [] _m;
- }
-
- MatrixBase& operator=(MatrixBase<Elem> const& a)
- {
- if (this == &a) return *this;
-
- this->newsize(a.num_rows(), a.num_cols());
-
- std::copy(a._m, a._m+_rows*_cols, _m);
- return *this;
- }
-
- void newsize(unsigned int rows, unsigned int cols)
- {
- if (rows == _rows && cols == _cols) return;
-
- assert(_ownsData);
-
- __destroy();
-
- _rows = rows;
- _cols = cols;
- if (_rows * _cols == 0) return;
- _m = new Elem[rows*cols];
- }
-
- unsigned int num_rows() const { return _rows; }
- unsigned int num_cols() const { return _cols; }
-
- Elem * operator[](unsigned int row) { return _m + row*_cols; }
- Elem const * operator[](unsigned int row) const { return _m + row*_cols; }
-
- Elem& operator()(unsigned int row, unsigned int col) { return _m[(row-1)*_cols + col-1]; }
- Elem operator()(unsigned int row, unsigned int col) const { return _m[(row-1)*_cols + col-1]; }
-
- const_iterator begin() const { return _m; }
- iterator begin() { return _m; }
- const_iterator end() const { return _m + _rows*_cols; }
- iterator end() { return _m + _rows*_cols; }
-
- template <typename Vec>
- void getRowSlice(unsigned int row, unsigned int first, unsigned int last, Vec& dst) const
- {
- Elem const * v = (*this)[row];
- for (unsigned int c = first; c < last; ++c) dst[c-first] = v[c];
- }
-
- template <typename Vec>
- void getColumnSlice(unsigned int first, unsigned int len, unsigned int col, Vec& dst) const
- {
- for (unsigned int r = 0; r < len; ++r) dst[r] = _m[r+first][col];
- }
-
- protected:
- void __destroy()
- {
- assert(_ownsData);
- if (_m != 0) delete [] _m;
- _m = 0;
- _rows = _cols = 0;
- }
-
- unsigned int _rows, _cols;
- bool _ownsData;
- Elem * _m;
- };
-
- template <typename T>
- struct CCS_Matrix
- {
- CCS_Matrix()
- : _rows(0), _cols(0)
- { }
-
- CCS_Matrix(int const rows, int const cols, vector<pair<int, int> > const& nonZeros)
- : _rows(rows), _cols(cols)
- {
- this->initialize(nonZeros);
- }
-
- CCS_Matrix(CCS_Matrix const& b)
- : _rows(b._rows), _cols(b._cols),
- _colStarts(b._colStarts), _rowIdxs(b._rowIdxs), _destIdxs(b._destIdxs), _values(b._values)
- { }
-
- CCS_Matrix& operator=(CCS_Matrix const& b)
- {
- if (this == &b) return *this;
- _rows = b._rows;
- _cols = b._cols;
- _colStarts = b._colStarts;
- _rowIdxs = b._rowIdxs;
- _destIdxs = b._destIdxs;
- _values = b._values;
- return *this;
- }
-
- void create(int const rows, int const cols, vector<pair<int, int> > const& nonZeros)
- {
- _rows = rows;
- _cols = cols;
- this->initialize(nonZeros);
- }
-
- unsigned int num_rows() const { return _rows; }
- unsigned int num_cols() const { return _cols; }
-
- int getNonzeroCount() const { return _values.size(); }
-
- T const * getValues() const { return &_values[0]; }
- T * getValues() { return &_values[0]; }
-
- int const * getDestIndices() const { return &_destIdxs[0]; }
- int const * getColumnStarts() const { return &_colStarts[0]; }
- int const * getRowIndices() const { return &_rowIdxs[0]; }
-
- void getRowRange(unsigned int col, unsigned int& firstRow, unsigned int& lastRow) const
- {
- firstRow = _rowIdxs[_colStarts[col]];
- lastRow = _rowIdxs[_colStarts[col+1]-1]+1;
- }
-
- template <typename Vec>
- void getColumnSlice(unsigned int first, unsigned int len, unsigned int col, Vec& dst) const
- {
- unsigned int const last = first + len;
-
- for (int r = 0; r < len; ++r) dst[r] = 0; // Fill vector with zeros
-
- int const colStart = _colStarts[col];
- int const colEnd = _colStarts[col+1];
-
- int i = colStart;
- int r;
- // Skip rows less than the given start row
- while (i < colEnd && (r = _rowIdxs[i]) < first) ++i;
-
- // Copy elements until the final row
- while (i < colEnd && (r = _rowIdxs[i]) < last)
- {
- dst[r-first] = _values[i];
- ++i;
- }
- } // end getColumnSlice()
-
- int getColumnNonzeroCount(unsigned int col) const
- {
- int const colStart = _colStarts[col];
- int const colEnd = _colStarts[col+1];
- return colEnd - colStart;
- }
-
- template <typename VecA, typename VecB>
- void getSparseColumn(unsigned int col, VecA& rows, VecB& values) const
- {
- int const colStart = _colStarts[col];
- int const colEnd = _colStarts[col+1];
- int const nnz = colEnd - colStart;
-
- for (int i = 0; i < nnz; ++i)
- {
- rows[i] = _rowIdxs[colStart + i];
- values[i] = _values[colStart + i];
- }
- }
-
- protected:
- struct NonzeroInfo
- {
- int row, col, serial;
-
- // Sort wrt the column first
- bool operator<(NonzeroInfo const& rhs) const
- {
- if (col < rhs.col) return true;
- if (col > rhs.col) return false;
- return row < rhs.row;
- }
- };
-
- void initialize(std::vector<std::pair<int, int> > const& nonZeros)
- {
- using namespace std;
-
- int const nnz = nonZeros.size();
-
- _colStarts.resize(_cols + 1);
- _rowIdxs.resize(nnz);
-
- vector<NonzeroInfo> nz(nnz);
- for (int k = 0; k < nnz; ++k)
- {
- nz[k].row = nonZeros[k].first;
- nz[k].col = nonZeros[k].second;
- nz[k].serial = k;
- }
-
- // Sort in column major order
- std::sort(nz.begin(), nz.end());
-
- for (size_t k = 0; k < nnz; ++k) _rowIdxs[k] = nz[k].row;
-
- int curCol = -1;
- for (int k = 0; k < nnz; ++k)
- {
- NonzeroInfo const& el = nz[k];
- if (el.col != curCol)
- {
- // Update empty cols between
- for (int c = curCol+1; c < el.col; ++c) _colStarts[c] = k;
-
- curCol = el.col;
- _colStarts[curCol] = k;
- } // end if
- } // end for (k)
-
- // Update remaining columns
- for (int c = curCol+1; c <= _cols; ++c) _colStarts[c] = nnz;
-
- _destIdxs.resize(nnz);
- for (int k = 0; k < nnz; ++k) _destIdxs[nz[k].serial] = k;
-
- _values.resize(nnz);
- } // end initialize()
-
- int _rows, _cols;
- std::vector<int> _colStarts;
- std::vector<int> _rowIdxs;
- std::vector<int> _destIdxs;
- std::vector<T> _values;
- }; // end struct CCS_Matrix
-
-//----------------------------------------------------------------------
-
- template <typename Vec, typename Elem>
- inline void
- fillVector(Vec& v, Elem val)
- {
- // We do not use std::fill since we rely only on size() and operator[] member functions.
- for (unsigned int i = 0; i < v.size(); ++i) v[i] = val;
- }
-
- template <typename Vec>
- inline void
- makeZeroVector(Vec& v)
- {
- fillVector(v, 0);
- }
-
- template <typename VecA, typename VecB>
- inline void
- copyVector(VecA const& src, VecB& dst)
- {
- assert(src.size() == dst.size());
- // We do not use std::fill since we rely only on size() and operator[] member functions.
- for (unsigned int i = 0; i < src.size(); ++i) dst[i] = src[i];
- }
-
- template <typename VecA, typename VecB>
- inline void
- copyVectorSlice(VecA const& src, unsigned int srcStart, unsigned int srcLen,
- VecB& dst, unsigned int dstStart)
- {
- unsigned int const end = std::min(srcStart + srcLen, src.size());
- unsigned int const sz = dst.size();
- unsigned int i0, i1;
- for (i0 = srcStart, i1 = dstStart; i0 < end && i1 < sz; ++i0, ++i1) dst[i1] = src[i0];
- }
-
- template <typename Vec>
- inline typename Vec::value_type
- norm_L1(Vec const& v)
- {
- typename Vec::value_type res(0);
- for (unsigned int i = 0; i < v.size(); ++i) res += fabs(v[i]);
- return res;
- }
-
- template <typename Vec>
- inline typename Vec::value_type
- norm_Linf(Vec const& v)
- {
- typename Vec::value_type res(0);
- for (unsigned int i = 0; i < v.size(); ++i) res = std::max(res, fabs(v[i]));
- return res;
- }
-
- template <typename Vec>
- inline typename Vec::value_type
- norm_L2(Vec const& v)
- {
- typename Vec::value_type res(0);
- for (unsigned int i = 0; i < v.size(); ++i) res += v[i]*v[i];
- return sqrt((double)res);
- }
-
- template <typename Vec>
- inline typename Vec::value_type
- sqrNorm_L2(Vec const& v)
- {
- typename Vec::value_type res(0);
- for (unsigned int i = 0; i < v.size(); ++i) res += v[i]*v[i];
- return res;
- }
-
- template <typename Vec>
- inline void
- normalizeVector(Vec& v)
- {
- typename Vec::value_type norm(norm_L2(v));
- for (unsigned int i = 0; i < v.size(); ++i) v[i] /= norm;
- }
-
- template<typename VecA, typename VecB>
- inline typename VecA::value_type
- innerProduct(VecA const& a, VecB const& b)
- {
- assert(a.size() == b.size());
- typename VecA::value_type res(0);
- for (unsigned int i = 0; i < a.size(); ++i) res += a[i] * b[i];
- return res;
- }
-
- template <typename Elem, typename VecA, typename VecB>
- inline void
- scaleVector(Elem s, VecA const& v, VecB& dst)
- {
- for (unsigned int i = 0; i < v.size(); ++i) dst[i] = s * v[i];
- }
-
- template <typename Elem, typename Vec>
- inline void
- scaleVectorIP(Elem s, Vec& v)
- {
- typedef typename Vec::value_type Elem2;
- for (unsigned int i = 0; i < v.size(); ++i)
- v[i] = (Elem2)(v[i] * s);
- }
-
- template <typename VecA, typename VecB, typename VecC>
- inline void
- makeCrossProductVector(VecA const& v, VecB const& w, VecC& dst)
- {
- assert(v.size() == 3);
- assert(w.size() == 3);
- assert(dst.size() == 3);
- dst[0] = v[1]*w[2] - v[2]*w[1];
- dst[1] = v[2]*w[0] - v[0]*w[2];
- dst[2] = v[0]*w[1] - v[1]*w[0];
- }
-
- template <typename VecA, typename VecB, typename VecC>
- inline void
- addVectors(VecA const& v, VecB const& w, VecC& dst)
- {
- assert(v.size() == w.size());
- assert(v.size() == dst.size());
- for (unsigned int i = 0; i < v.size(); ++i) dst[i] = v[i] + w[i];
- }
-
- template <typename VecA, typename VecB, typename VecC>
- inline void
- subtractVectors(VecA const& v, VecB const& w, VecC& dst)
- {
- assert(v.size() == w.size());
- assert(v.size() == dst.size());
- for (unsigned int i = 0; i < v.size(); ++i) dst[i] = v[i] - w[i];
- }
-
- template <typename MatA, typename MatB>
- inline void
- copyMatrix(MatA const& src, MatB& dst)
- {
- unsigned int const rows = src.num_rows();
- unsigned int const cols = src.num_cols();
- assert(dst.num_rows() == rows);
- assert(dst.num_cols() == cols);
- for (unsigned int c = 0; c < cols; ++c)
- for (unsigned int r = 0; r < rows; ++r) dst[r][c] = src[r][c];
- }
-
- template <typename MatA, typename MatB>
- inline void
- copyMatrixSlice(MatA const& src, unsigned int rowStart, unsigned int colStart, unsigned int rowLen, unsigned int colLen,
- MatB& dst, unsigned int dstRow, unsigned int dstCol)
- {
- unsigned int const rows = dst.num_rows();
- unsigned int const cols = dst.num_cols();
-
- unsigned int const rowEnd = std::min(rowStart + rowLen, src.num_rows());
- unsigned int const colEnd = std::min(colStart + colLen, src.num_cols());
-
- unsigned int c0, c1, r0, r1;
-
- for (c0 = colStart, c1 = dstCol; c0 < colEnd && c1 < cols; ++c0, ++c1)
- for (r0 = rowStart, r1 = dstRow; r0 < rowEnd && r1 < rows; ++r0, ++r1)
- dst[r1][c1] = src[r0][c0];
- }
-
- template <typename MatA, typename MatB>
- inline void
- makeTransposedMatrix(MatA const& src, MatB& dst)
- {
- unsigned int const rows = src.num_rows();
- unsigned int const cols = src.num_cols();
- assert(dst.num_cols() == rows);
- assert(dst.num_rows() == cols);
- for (unsigned int c = 0; c < cols; ++c)
- for (unsigned int r = 0; r < rows; ++r) dst[c][r] = src[r][c];
- }
-
- template <typename Mat>
- inline void
- fillMatrix(Mat& m, typename Mat::value_type val)
- {
- unsigned int const rows = m.num_rows();
- unsigned int const cols = m.num_cols();
- for (unsigned int c = 0; c < cols; ++c)
- for (unsigned int r = 0; r < rows; ++r) m[r][c] = val;
- }
-
- template <typename Mat>
- inline void
- makeZeroMatrix(Mat& m)
- {
- fillMatrix(m, 0);
- }
-
- template <typename Mat>
- inline void
- makeIdentityMatrix(Mat& m)
- {
- makeZeroMatrix(m);
- unsigned int const rows = m.num_rows();
- unsigned int const cols = m.num_cols();
- unsigned int n = std::min(rows, cols);
- for (unsigned int i = 0; i < n; ++i)
- m[i][i] = 1;
- }
-
- template <typename Mat, typename Vec>
- inline void
- makeCrossProductMatrix(Vec const& v, Mat& m)
- {
- assert(v.size() == 3);
- assert(m.num_rows() == 3);
- assert(m.num_cols() == 3);
- m[0][0] = 0; m[0][1] = -v[2]; m[0][2] = v[1];
- m[1][0] = v[2]; m[1][1] = 0; m[1][2] = -v[0];
- m[2][0] = -v[1]; m[2][1] = v[0]; m[2][2] = 0;
- }
-
- template <typename Mat, typename Vec>
- inline void
- makeOuterProductMatrix(Vec const& v, Mat& m)
- {
- assert(m.num_cols() == m.num_rows());
- assert(v.size() == m.num_cols());
- unsigned const sz = v.size();
- for (unsigned r = 0; r < sz; ++r)
- for (unsigned c = 0; c < sz; ++c) m[r][c] = v[r]*v[c];
- }
-
- template <typename Mat, typename VecA, typename VecB>
- inline void
- makeOuterProductMatrix(VecA const& u, VecB const& v, Mat& m)
- {
- assert(m.num_cols() == m.num_rows());
- assert(u.size() == m.num_cols());
- assert(v.size() == m.num_cols());
- unsigned const sz = u.size();
- for (unsigned r = 0; r < sz; ++r)
- for (unsigned c = 0; c < sz; ++c) m[r][c] = u[r]*v[c];
- }
-
- template <typename MatA, typename MatB, typename MatC>
- void addMatrices(MatA const& a, MatB const& b, MatC& dst)
- {
- assert(a.num_cols() == b.num_cols());
- assert(a.num_rows() == b.num_rows());
- assert(dst.num_cols() == a.num_cols());
- assert(dst.num_rows() == a.num_rows());
-
- unsigned int const rows = a.num_rows();
- unsigned int const cols = a.num_cols();
-
- for (unsigned r = 0; r < rows; ++r)
- for (unsigned c = 0; c < cols; ++c) dst[r][c] = a[r][c] + b[r][c];
- }
-
- template <typename MatA, typename MatB>
- void addMatricesIP(MatA const& a, MatB& dst)
- {
- assert(dst.num_cols() == a.num_cols());
- assert(dst.num_rows() == a.num_rows());
-
- unsigned int const rows = a.num_rows();
- unsigned int const cols = a.num_cols();
-
- for (unsigned r = 0; r < rows; ++r)
- for (unsigned c = 0; c < cols; ++c) dst[r][c] += a[r][c];
- }
-
- template <typename MatA, typename MatB, typename MatC>
- void subtractMatrices(MatA const& a, MatB const& b, MatC& dst)
- {
- assert(a.num_cols() == b.num_cols());
- assert(a.num_rows() == b.num_rows());
- assert(dst.num_cols() == a.num_cols());
- assert(dst.num_rows() == a.num_rows());
-
- unsigned int const rows = a.num_rows();
- unsigned int const cols = a.num_cols();
-
- for (unsigned r = 0; r < rows; ++r)
- for (unsigned c = 0; c < cols; ++c) dst[r][c] = a[r][c] - b[r][c];
- }
-
- template <typename MatA, typename Elem, typename MatB>
- inline void
- makeScaledMatrix(MatA const& m, Elem scale, MatB& dst)
- {
- unsigned int const rows = m.num_rows();
- unsigned int const cols = m.num_cols();
- for (unsigned int c = 0; c < cols; ++c)
- for (unsigned int r = 0; r < rows; ++r) dst[r][c] = m[r][c] * scale;
- }
-
- template <typename Mat, typename Elem>
- inline void
- scaleMatrixIP(Elem scale, Mat& m)
- {
- unsigned int const rows = m.num_rows();
- unsigned int const cols = m.num_cols();
- for (unsigned int c = 0; c < cols; ++c)
- for (unsigned int r = 0; r < rows; ++r) m[r][c] *= scale;
- }
-
- template <typename Mat, typename VecA, typename VecB>
- inline void
- multiply_A_v(Mat const& m, VecA const& in, VecB& dst)
- {
- unsigned int const rows = m.num_rows();
- unsigned int const cols = m.num_cols();
- assert(in.size() == cols);
- assert(dst.size() == rows);
-
- makeZeroVector(dst);
-
- for (unsigned int r = 0; r < rows; ++r)
- for (unsigned int c = 0; c < cols; ++c) dst[r] += m[r][c] * in[c];
- }
-
- template <typename Mat, typename VecA, typename VecB>
- inline void
- multiply_A_v_projective(Mat const& m, VecA const& in, VecB& dst)
- {
- unsigned int const rows = m.num_rows();
- unsigned int const cols = m.num_cols();
- assert(in.size() == cols-1);
- assert(dst.size() == rows-1);
-
- typename VecB::value_type w = m(rows-1, cols-1);
- unsigned int r, i;
- for (i = 0; i < cols-1; ++i) w += m(rows-1, i) * in[i];
- for (r = 0; r < rows-1; ++r) dst[r] = m(r, cols-1);
- for (r = 0; r < rows-1; ++r)
- for (unsigned int c = 0; c < cols-1; ++c) dst[r] += m[r][c] * in[c];
- for (i = 0; i < rows-1; ++i) dst[i] /= w;
- }
-
- template <typename Mat, typename VecA, typename VecB>
- inline void
- multiply_A_v_affine(Mat const& m, VecA const& in, VecB& dst)
- {
- unsigned int const rows = m.num_rows();
- unsigned int const cols = m.num_cols();
- assert(in.size() == cols-1);
- assert(dst.size() == rows);
-
- unsigned int r;
-
- for (r = 0; r < rows; ++r) dst[r] = m(r, cols-1);
- for (r = 0; r < rows; ++r)
- for (unsigned int c = 0; c < cols-1; ++c) dst[r] += m[r][c] * in[c];
- }
-
- template <typename Mat, typename VecA, typename VecB>
- inline void
- multiply_At_v(Mat const& m, VecA const& in, VecB& dst)
- {
- unsigned int const rows = m.num_rows();
- unsigned int const cols = m.num_cols();
- assert(in.size() == rows);
- assert(dst.size() == cols);
-
- makeZeroVector(dst);
- for (unsigned int c = 0; c < cols; ++c)
- for (unsigned int r = 0; r < rows; ++r) dst[c] += m[r][c] * in[r];
- }
-
- template <typename MatA, typename MatB>
- inline void
- multiply_At_A(MatA const& a, MatB& dst)
- {
- assert(dst.num_rows() == a.num_cols());
- assert(dst.num_cols() == a.num_cols());
-
- typedef typename MatB::value_type Elem;
-
- Elem accum;
- for (unsigned int r = 0; r < a.num_cols(); ++r)
- for (unsigned int c = 0; c < a.num_cols(); ++c)
- {
- accum = 0;
- for (unsigned int k = 0; k < a.num_rows(); ++k) accum += a[k][r] * a[k][c];
- dst[r][c] = accum;
- }
- }
-
- template <typename MatA, typename MatB, typename MatC>
- inline void
- multiply_A_B(MatA const& a, MatB const& b, MatC& dst)
- {
- assert(a.num_cols() == b.num_rows());
- assert(dst.num_rows() == a.num_rows());
- assert(dst.num_cols() == b.num_cols());
-
- typedef typename MatC::value_type Elem;
-
- Elem accum;
- for (unsigned int r = 0; r < a.num_rows(); ++r)
- for (unsigned int c = 0; c < b.num_cols(); ++c)
- {
- accum = 0;
- for (unsigned int k = 0; k < a.num_cols(); ++k) accum += a[r][k] * b[k][c];
- dst[r][c] = accum;
- }
- }
-
- template <typename MatA, typename MatB, typename MatC>
- inline void
- multiply_At_B(MatA const& a, MatB const& b, MatC& dst)
- {
- assert(a.num_rows() == b.num_rows());
- assert(dst.num_rows() == a.num_cols());
- assert(dst.num_cols() == b.num_cols());
-
- typedef typename MatC::value_type Elem;
-
- Elem accum;
- for (unsigned int r = 0; r < a.num_cols(); ++r)
- for (unsigned int c = 0; c < b.num_cols(); ++c)
- {
- accum = 0;
- for (unsigned int k = 0; k < a.num_rows(); ++k) accum += a[k][r] * b[k][c];
- dst[r][c] = accum;
- }
- }
-
- template <typename MatA, typename MatB, typename MatC>
- inline void
- multiply_A_Bt(MatA const& a, MatB const& b, MatC& dst)
- {
- assert(a.num_cols() == b.num_cols());
- assert(dst.num_rows() == a.num_rows());
- assert(dst.num_cols() == b.num_rows());
-
- typedef typename MatC::value_type Elem;
-
- Elem accum;
- for (unsigned int r = 0; r < a.num_rows(); ++r)
- for (unsigned int c = 0; c < b.num_rows(); ++c)
- {
- accum = 0;
- for (unsigned int k = 0; k < a.num_cols(); ++k) accum += a[r][k] * b[c][k];
- dst[r][c] = accum;
- }
- }
-
- template <typename Mat>
- inline void
- transposeMatrixIP(Mat& a)
- {
- assert(a.num_rows() == a.num_cols());
-
- for (unsigned int r = 0; r < a.num_rows(); ++r)
- for (unsigned int c = 0; c < r; ++c)
- std::swap(a[r][c], a[c][r]);
- }
-
-} // end namespace V3D
-
-#endif
diff --git a/extern/libmv/third_party/ssba/Math/v3d_linear_utils.h b/extern/libmv/third_party/ssba/Math/v3d_linear_utils.h
deleted file mode 100644
index 969ec99694f..00000000000
--- a/extern/libmv/third_party/ssba/Math/v3d_linear_utils.h
+++ /dev/null
@@ -1,391 +0,0 @@
-// -*- C++ -*-
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA 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.
-
-SSBA is distributed in the hope that 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 SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef V3D_LINEAR_UTILS_H
-#define V3D_LINEAR_UTILS_H
-
-#include "Math/v3d_linear.h"
-
-#include <iostream>
-
-namespace V3D
-{
-
- template <typename Elem, int Size>
- struct InlineVector : public InlineVectorBase<Elem, Size>
- {
- }; // end struct InlineVector
-
- template <typename Elem>
- struct Vector : public VectorBase<Elem>
- {
- Vector()
- : VectorBase<Elem>()
- { }
-
- Vector(unsigned int size)
- : VectorBase<Elem>(size)
- { }
-
- Vector(unsigned int size, Elem * values)
- : VectorBase<Elem>(size, values)
- { }
-
- Vector(Vector<Elem> const& a)
- : VectorBase<Elem>(a)
- { }
-
- Vector<Elem>& operator=(Vector<Elem> const& a)
- {
- (VectorBase<Elem>::operator=)(a);
- return *this;
- }
-
- Vector<Elem>& operator+=(Vector<Elem> const& rhs)
- {
- addVectorsIP(rhs, *this);
- return *this;
- }
-
- Vector<Elem>& operator*=(Elem scale)
- {
- scaleVectorsIP(scale, *this);
- return *this;
- }
-
- Vector<Elem> operator+(Vector<Elem> const& rhs) const
- {
- Vector<Elem> res(this->size());
- addVectors(*this, rhs, res);
- return res;
- }
-
- Vector<Elem> operator-(Vector<Elem> const& rhs) const
- {
- Vector<Elem> res(this->size());
- subtractVectors(*this, rhs, res);
- return res;
- }
-
- Elem operator*(Vector<Elem> const& rhs) const
- {
- return innerProduct(*this, rhs);
- }
-
- }; // end struct Vector
-
- template <typename Elem, int Rows, int Cols>
- struct InlineMatrix : public InlineMatrixBase<Elem, Rows, Cols>
- {
- }; // end struct InlineMatrix
-
- template <typename Elem>
- struct Matrix : public MatrixBase<Elem>
- {
- Matrix()
- : MatrixBase<Elem>()
- { }
-
- Matrix(unsigned int rows, unsigned int cols)
- : MatrixBase<Elem>(rows, cols)
- { }
-
- Matrix(unsigned int rows, unsigned int cols, Elem * values)
- : MatrixBase<Elem>(rows, cols, values)
- { }
-
- Matrix(Matrix<Elem> const& a)
- : MatrixBase<Elem>(a)
- { }
-
- Matrix<Elem>& operator=(Matrix<Elem> const& a)
- {
- (MatrixBase<Elem>::operator=)(a);
- return *this;
- }
-
- Matrix<Elem>& operator+=(Matrix<Elem> const& rhs)
- {
- addMatricesIP(rhs, *this);
- return *this;
- }
-
- Matrix<Elem>& operator*=(Elem scale)
- {
- scaleMatrixIP(scale, *this);
- return *this;
- }
-
- Matrix<Elem> operator+(Matrix<Elem> const& rhs) const
- {
- Matrix<Elem> res(this->num_rows(), this->num_cols());
- addMatrices(*this, rhs, res);
- return res;
- }
-
- Matrix<Elem> operator-(Matrix<Elem> const& rhs) const
- {
- Matrix<Elem> res(this->num_rows(), this->num_cols());
- subtractMatrices(*this, rhs, res);
- return res;
- }
-
- }; // end struct Matrix
-
-//----------------------------------------------------------------------
-
- typedef InlineVector<float, 2> Vector2f;
- typedef InlineVector<double, 2> Vector2d;
- typedef InlineVector<float, 3> Vector3f;
- typedef InlineVector<double, 3> Vector3d;
- typedef InlineVector<float, 4> Vector4f;
- typedef InlineVector<double, 4> Vector4d;
-
- typedef InlineMatrix<float, 2, 2> Matrix2x2f;
- typedef InlineMatrix<double, 2, 2> Matrix2x2d;
- typedef InlineMatrix<float, 3, 3> Matrix3x3f;
- typedef InlineMatrix<double, 3, 3> Matrix3x3d;
- typedef InlineMatrix<float, 4, 4> Matrix4x4f;
- typedef InlineMatrix<double, 4, 4> Matrix4x4d;
-
- typedef InlineMatrix<float, 2, 3> Matrix2x3f;
- typedef InlineMatrix<double, 2, 3> Matrix2x3d;
- typedef InlineMatrix<float, 3, 4> Matrix3x4f;
- typedef InlineMatrix<double, 3, 4> Matrix3x4d;
-
- template <typename Elem>
- struct VectorArray
- {
- VectorArray(unsigned count, unsigned size)
- : _count(count), _size(size), _values(0), _vectors(0)
- {
- unsigned const nTotal = _count * _size;
- if (count > 0) _vectors = new Vector<Elem>[count];
- if (nTotal > 0) _values = new Elem[nTotal];
- for (unsigned i = 0; i < _count; ++i) new (&_vectors[i]) Vector<Elem>(_size, _values + i*_size);
- }
-
- VectorArray(unsigned count, unsigned size, Elem initVal)
- : _count(count), _size(size), _values(0), _vectors(0)
- {
- unsigned const nTotal = _count * _size;
- if (count > 0) _vectors = new Vector<Elem>[count];
- if (nTotal > 0) _values = new Elem[nTotal];
- for (unsigned i = 0; i < _count; ++i) new (&_vectors[i]) Vector<Elem>(_size, _values + i*_size);
- std::fill(_values, _values + nTotal, initVal);
- }
-
- ~VectorArray()
- {
- delete [] _values;
- delete [] _vectors;
- }
-
- unsigned count() const { return _count; }
- unsigned size() const { return _size; }
-
- //! Get the submatrix at position ix
- Vector<Elem> const& operator[](unsigned ix) const
- {
- return _vectors[ix];
- }
-
- //! Get the submatrix at position ix
- Vector<Elem>& operator[](unsigned ix)
- {
- return _vectors[ix];
- }
-
- protected:
- unsigned _count, _size;
- Elem * _values;
- Vector<Elem> * _vectors;
-
- private:
- VectorArray(VectorArray const&);
- void operator=(VectorArray const&);
- };
-
- template <typename Elem>
- struct MatrixArray
- {
- MatrixArray(unsigned count, unsigned nRows, unsigned nCols)
- : _count(count), _rows(nRows), _columns(nCols), _values(0), _matrices(0)
- {
- unsigned const nTotal = _count * _rows * _columns;
- if (count > 0) _matrices = new Matrix<Elem>[count];
- if (nTotal > 0) _values = new double[nTotal];
- for (unsigned i = 0; i < _count; ++i)
- new (&_matrices[i]) Matrix<Elem>(_rows, _columns, _values + i*(_rows*_columns));
- }
-
- ~MatrixArray()
- {
- delete [] _matrices;
- delete [] _values;
- }
-
- //! Get the submatrix at position ix
- Matrix<Elem> const& operator[](unsigned ix) const
- {
- return _matrices[ix];
- }
-
- //! Get the submatrix at position ix
- Matrix<Elem>& operator[](unsigned ix)
- {
- return _matrices[ix];
- }
-
- unsigned count() const { return _count; }
- unsigned num_rows() const { return _rows; }
- unsigned num_cols() const { return _columns; }
-
- protected:
- unsigned _count, _rows, _columns;
- double * _values;
- Matrix<Elem> * _matrices;
-
- private:
- MatrixArray(MatrixArray const&);
- void operator=(MatrixArray const&);
- };
-
-//----------------------------------------------------------------------
-
- template <typename Elem, int Size>
- inline InlineVector<Elem, Size>
- operator+(InlineVector<Elem, Size> const& v, InlineVector<Elem, Size> const& w)
- {
- InlineVector<Elem, Size> res;
- addVectors(v, w, res);
- return res;
- }
-
- template <typename Elem, int Size>
- inline InlineVector<Elem, Size>
- operator-(InlineVector<Elem, Size> const& v, InlineVector<Elem, Size> const& w)
- {
- InlineVector<Elem, Size> res;
- subtractVectors(v, w, res);
- return res;
- }
-
- template <typename Elem, int Size>
- inline InlineVector<Elem, Size>
- operator*(Elem scale, InlineVector<Elem, Size> const& v)
- {
- InlineVector<Elem, Size> res;
- scaleVector(scale, v, res);
- return res;
- }
-
- template <typename Elem, int Rows, int Cols>
- inline InlineVector<Elem, Rows>
- operator*(InlineMatrix<Elem, Rows, Cols> const& A, InlineVector<Elem, Cols> const& v)
- {
- InlineVector<Elem, Rows> res;
- multiply_A_v(A, v, res);
- return res;
- }
-
- template <typename Elem, int RowsA, int ColsA, int ColsB>
- inline InlineMatrix<Elem, RowsA, ColsB>
- operator*(InlineMatrix<Elem, RowsA, ColsA> const& A, InlineMatrix<Elem, ColsA, ColsB> const& B)
- {
- InlineMatrix<Elem, RowsA, ColsB> res;
- multiply_A_B(A, B, res);
- return res;
- }
-
- template <typename Elem, int Rows, int Cols>
- inline InlineMatrix<Elem, Cols, Rows>
- transposedMatrix(InlineMatrix<Elem, Rows, Cols> const& A)
- {
- InlineMatrix<Elem, Cols, Rows> At;
- makeTransposedMatrix(A, At);
- return At;
- }
-
- template <typename Elem>
- inline InlineMatrix<Elem, 3, 3>
- invertedMatrix(InlineMatrix<Elem, 3, 3> const& A)
- {
- Elem a = A[0][0], b = A[0][1], c = A[0][2];
- Elem d = A[1][0], e = A[1][1], f = A[1][2];
- Elem g = A[2][0], h = A[2][1], i = A[2][2];
-
- Elem const det = a*e*i + b*f*g + c*d*h - c*e*g - b*d*i - a*f*h;
-
- InlineMatrix<Elem, 3, 3> res;
- res[0][0] = e*i-f*h; res[0][1] = c*h-b*i; res[0][2] = b*f-c*e;
- res[1][0] = f*g-d*i; res[1][1] = a*i-c*g; res[1][2] = c*d-a*f;
- res[2][0] = d*h-e*g; res[2][1] = b*g-a*h; res[2][2] = a*e-b*d;
-
- scaleMatrixIP(1.0/det, res);
- return res;
- }
-
- template <typename Elem>
- inline InlineVector<Elem, 2>
- makeVector2(Elem a, Elem b)
- {
- InlineVector<Elem, 2> res;
- res[0] = a; res[1] = b;
- return res;
- }
-
- template <typename Elem>
- inline InlineVector<Elem, 3>
- makeVector3(Elem a, Elem b, Elem c)
- {
- InlineVector<Elem, 3> res;
- res[0] = a; res[1] = b; res[2] = c;
- return res;
- }
-
- template <typename Vec>
- inline void
- displayVector(Vec const& v)
- {
- using namespace std;
-
- for (int r = 0; r < v.size(); ++r)
- cout << v[r] << " ";
- cout << endl;
- }
-
- template <typename Mat>
- inline void
- displayMatrix(Mat const& A)
- {
- using namespace std;
-
- for (int r = 0; r < A.num_rows(); ++r)
- {
- for (int c = 0; c < A.num_cols(); ++c)
- cout << A[r][c] << " ";
- cout << endl;
- }
- }
-
-} // end namespace V3D
-
-#endif
diff --git a/extern/libmv/third_party/ssba/Math/v3d_mathutilities.h b/extern/libmv/third_party/ssba/Math/v3d_mathutilities.h
deleted file mode 100644
index 9e38b92a94b..00000000000
--- a/extern/libmv/third_party/ssba/Math/v3d_mathutilities.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// -*- C++ -*-
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA 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.
-
-SSBA is distributed in the hope that 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 SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef V3D_MATH_UTILITIES_H
-#define V3D_MATH_UTILITIES_H
-
-#include "Math/v3d_linear.h"
-#include "Math/v3d_linear_utils.h"
-
-#include <vector>
-
-namespace V3D
-{
-
- template <typename Vec, typename Mat>
- inline void
- createRotationMatrixRodriguez(Vec const& omega, Mat& R)
- {
- assert(omega.size() == 3);
- assert(R.num_rows() == 3);
- assert(R.num_cols() == 3);
-
- double const theta = norm_L2(omega);
- makeIdentityMatrix(R);
- if (fabs(theta) > 1e-6)
- {
- Matrix3x3d J, J2;
- makeCrossProductMatrix(omega, J);
- multiply_A_B(J, J, J2);
- double const c1 = sin(theta)/theta;
- double const c2 = (1-cos(theta))/(theta*theta);
- for (int i = 0; i < 3; ++i)
- for (int j = 0; j < 3; ++j)
- R[i][j] += c1*J[i][j] + c2*J2[i][j];
- }
- } // end createRotationMatrixRodriguez()
-
- template <typename T> inline double sqr(T x) { return x*x; }
-
-} // namespace V3D
-
-#endif
diff --git a/extern/libmv/third_party/ssba/Math/v3d_optimization.cpp b/extern/libmv/third_party/ssba/Math/v3d_optimization.cpp
deleted file mode 100644
index 234815fcd1f..00000000000
--- a/extern/libmv/third_party/ssba/Math/v3d_optimization.cpp
+++ /dev/null
@@ -1,955 +0,0 @@
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA 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.
-
-SSBA is distributed in the hope that 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 SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "Math/v3d_optimization.h"
-
-#if defined(V3DLIB_ENABLE_SUITESPARSE)
-//# include "COLAMD/Include/colamd.h"
-# include "colamd.h"
-extern "C"
-{
-//# include "LDL/Include/ldl.h"
-# include "ldl.h"
-}
-#endif
-
-#include <iostream>
-#include <map>
-
-#define USE_BLOCK_REORDERING 1
-#define USE_MULTIPLICATIVE_UPDATE 1
-
-using namespace std;
-
-namespace
-{
-
- using namespace V3D;
-
- inline double
- squaredResidual(VectorArray<double> const& e)
- {
- int const N = e.count();
- int const M = e.size();
-
- double res = 0.0;
-
- for (int n = 0; n < N; ++n)
- for (int m = 0; m < M; ++m)
- res += e[n][m] * e[n][m];
-
- return res;
- } // end squaredResidual()
-
-} // end namespace <>
-
-namespace V3D
-{
-
- int optimizerVerbosenessLevel = 0;
-
-#if defined(V3DLIB_ENABLE_SUITESPARSE)
-
- void
- SparseLevenbergOptimizer::setupSparseJtJ()
- {
- int const nVaryingA = _nParametersA - _nNonvaryingA;
- int const nVaryingB = _nParametersB - _nNonvaryingB;
- int const nVaryingC = _paramDimensionC - _nNonvaryingC;
-
- int const bColumnStart = nVaryingA*_paramDimensionA;
- int const cColumnStart = bColumnStart + nVaryingB*_paramDimensionB;
- int const nColumns = cColumnStart + nVaryingC;
-
- _jointNonzerosW.clear();
- _jointIndexW.resize(_nMeasurements);
-#if 1
- {
- map<pair<int, int>, int> jointNonzeroMap;
- for (size_t k = 0; k < _nMeasurements; ++k)
- {
- int const i = _correspondingParamA[k] - _nNonvaryingA;
- int const j = _correspondingParamB[k] - _nNonvaryingB;
- if (i >= 0 && j >= 0)
- {
- map<pair<int, int>, int>::const_iterator p = jointNonzeroMap.find(make_pair(i, j));
- if (p == jointNonzeroMap.end())
- {
- jointNonzeroMap.insert(make_pair(make_pair(i, j), _jointNonzerosW.size()));
- _jointIndexW[k] = _jointNonzerosW.size();
- _jointNonzerosW.push_back(make_pair(i, j));
- }
- else
- {
- _jointIndexW[k] = (*p).second;
- } // end if
- } // end if
- } // end for (k)
- } // end scope
-#else
- for (size_t k = 0; k < _nMeasurements; ++k)
- {
- int const i = _correspondingParamA[k] - _nNonvaryingA;
- int const j = _correspondingParamB[k] - _nNonvaryingB;
- if (i >= 0 && j >= 0)
- {
- _jointIndexW[k] = _jointNonzerosW.size();
- _jointNonzerosW.push_back(make_pair(i, j));
- }
- } // end for (k)
-#endif
-
-#if defined(USE_BLOCK_REORDERING)
- int const bBlockColumnStart = nVaryingA;
- int const cBlockColumnStart = bBlockColumnStart + nVaryingB;
-
- int const nBlockColumns = cBlockColumnStart + ((nVaryingC > 0) ? 1 : 0);
-
- //cout << "nBlockColumns = " << nBlockColumns << endl;
-
- // For the column reordering we treat the columns belonging to one set
- // of parameters as one (logical) column.
-
- // Determine non-zeros of JtJ (we forget about the non-zero diagonal for now)
- // Only consider nonzeros of Ai^t * Bj induced by the measurements.
- vector<pair<int, int> > nz_blockJtJ(_jointNonzerosW.size());
- for (int k = 0; k < _jointNonzerosW.size(); ++k)
- {
- nz_blockJtJ[k].first = _jointNonzerosW[k].second + bBlockColumnStart;
- nz_blockJtJ[k].second = _jointNonzerosW[k].first;
- }
-
- if (nVaryingC > 0)
- {
- // We assume, that the global unknowns are linked to every other variable.
- for (int i = 0; i < nVaryingA; ++i)
- nz_blockJtJ.push_back(make_pair(cBlockColumnStart, i));
- for (int j = 0; j < nVaryingB; ++j)
- nz_blockJtJ.push_back(make_pair(cBlockColumnStart, j + bBlockColumnStart));
- } // end if
-
- int const nnzBlock = nz_blockJtJ.size();
-
- vector<int> permBlockJtJ(nBlockColumns + 1);
-
- if (nnzBlock > 0)
- {
-// cout << "nnzBlock = " << nnzBlock << endl;
-
- CCS_Matrix<int> blockJtJ(nBlockColumns, nBlockColumns, nz_blockJtJ);
-
-// cout << " nz_blockJtJ: " << endl;
-// for (size_t k = 0; k < nz_blockJtJ.size(); ++k)
-// cout << " " << nz_blockJtJ[k].first << ":" << nz_blockJtJ[k].second << endl;
-// cout << endl;
-
- int * colStarts = (int *)blockJtJ.getColumnStarts();
- int * rowIdxs = (int *)blockJtJ.getRowIndices();
-
-// cout << "blockJtJ_colStarts = ";
-// for (int k = 0; k <= nBlockColumns; ++k) cout << colStarts[k] << " ";
-// cout << endl;
-
-// cout << "blockJtJ_rowIdxs = ";
-// for (int k = 0; k < nnzBlock; ++k) cout << rowIdxs[k] << " ";
-// cout << endl;
-
- int stats[COLAMD_STATS];
- symamd(nBlockColumns, rowIdxs, colStarts, &permBlockJtJ[0], (double *) NULL, stats, &calloc, &free);
- if (optimizerVerbosenessLevel >= 2) symamd_report(stats);
- }
- else
- {
- for (int k = 0; k < permBlockJtJ.size(); ++k) permBlockJtJ[k] = k;
- } // end if
-
-// cout << "permBlockJtJ = ";
-// for (int k = 0; k < permBlockJtJ.size(); ++k)
-// cout << permBlockJtJ[k] << " ";
-// cout << endl;
-
- // From the determined symbolic permutation with logical variables, determine the actual ordering
- _perm_JtJ.resize(nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB + nVaryingC + 1);
-
- int curDstCol = 0;
- for (int k = 0; k < permBlockJtJ.size()-1; ++k)
- {
- int const srcCol = permBlockJtJ[k];
- if (srcCol < nVaryingA)
- {
- for (int n = 0; n < _paramDimensionA; ++n)
- _perm_JtJ[curDstCol + n] = srcCol*_paramDimensionA + n;
- curDstCol += _paramDimensionA;
- }
- else if (srcCol >= bBlockColumnStart && srcCol < cBlockColumnStart)
- {
- int const bStart = nVaryingA*_paramDimensionA;
- int const j = srcCol - bBlockColumnStart;
-
- for (int n = 0; n < _paramDimensionB; ++n)
- _perm_JtJ[curDstCol + n] = bStart + j*_paramDimensionB + n;
- curDstCol += _paramDimensionB;
- }
- else if (srcCol == cBlockColumnStart)
- {
- int const cStart = nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB;
-
- for (int n = 0; n < nVaryingC; ++n)
- _perm_JtJ[curDstCol + n] = cStart + n;
- curDstCol += nVaryingC;
- }
- else
- {
- cerr << "Should not reach " << __LINE__ << ":" << __LINE__ << "!" << endl;
- assert(false);
- }
- }
-#else
- vector<pair<int, int> > nz, nzL;
- this->serializeNonZerosJtJ(nz);
-
- for (int k = 0; k < nz.size(); ++k)
- {
- // Swap rows and columns, since serializeNonZerosJtJ() generates the
- // upper triangular part but symamd wants the lower triangle.
- nzL.push_back(make_pair(nz[k].second, nz[k].first));
- }
-
- _perm_JtJ.resize(nColumns+1);
-
- if (nzL.size() > 0)
- {
- CCS_Matrix<int> symbJtJ(nColumns, nColumns, nzL);
-
- int * colStarts = (int *)symbJtJ.getColumnStarts();
- int * rowIdxs = (int *)symbJtJ.getRowIndices();
-
-// cout << "symbJtJ_colStarts = ";
-// for (int k = 0; k <= nColumns; ++k) cout << colStarts[k] << " ";
-// cout << endl;
-
-// cout << "symbJtJ_rowIdxs = ";
-// for (int k = 0; k < nzL.size(); ++k) cout << rowIdxs[k] << " ";
-// cout << endl;
-
- int stats[COLAMD_STATS];
- symamd(nColumns, rowIdxs, colStarts, &_perm_JtJ[0], (double *) NULL, stats, &calloc, &free);
- if (optimizerVerbosenessLevel >= 2) symamd_report(stats);
- }
- else
- {
- for (int k = 0; k < _perm_JtJ.size(); ++k) _perm_JtJ[k] = k;
- } //// end if
-#endif
- _perm_JtJ.back() = _perm_JtJ.size() - 1;
-
-// cout << "_perm_JtJ = ";
-// for (int k = 0; k < _perm_JtJ.size(); ++k) cout << _perm_JtJ[k] << " ";
-// cout << endl;
-
- // Finally, compute the inverse of the full permutation.
- _invPerm_JtJ.resize(_perm_JtJ.size());
- for (size_t k = 0; k < _perm_JtJ.size(); ++k)
- _invPerm_JtJ[_perm_JtJ[k]] = k;
-
- vector<pair<int, int> > nz_JtJ;
- this->serializeNonZerosJtJ(nz_JtJ);
-
- for (int k = 0; k < nz_JtJ.size(); ++k)
- {
- int const i = nz_JtJ[k].first;
- int const j = nz_JtJ[k].second;
-
- int pi = _invPerm_JtJ[i];
- int pj = _invPerm_JtJ[j];
- // Swap values if in lower triangular part
- if (pi > pj) std::swap(pi, pj);
- nz_JtJ[k].first = pi;
- nz_JtJ[k].second = pj;
- }
-
- int const nnz = nz_JtJ.size();
-
-// cout << "nz_JtJ = ";
-// for (int k = 0; k < nnz; ++k) cout << nz_JtJ[k].first << ":" << nz_JtJ[k].second << " ";
-// cout << endl;
-
- _JtJ.create(nColumns, nColumns, nz_JtJ);
-
-// cout << "_colStart_JtJ = ";
-// for (int k = 0; k < _JtJ.num_cols(); ++k) cout << _JtJ.getColumnStarts()[k] << " ";
-// cout << endl;
-
-// cout << "_rowIdxs_JtJ = ";
-// for (int k = 0; k < nnz; ++k) cout << _JtJ.getRowIndices()[k] << " ";
-// cout << endl;
-
- vector<int> workFlags(nColumns);
-
- _JtJ_Lp.resize(nColumns+1);
- _JtJ_Parent.resize(nColumns);
- _JtJ_Lnz.resize(nColumns);
-
- ldl_symbolic(nColumns, (int *)_JtJ.getColumnStarts(), (int *)_JtJ.getRowIndices(),
- &_JtJ_Lp[0], &_JtJ_Parent[0], &_JtJ_Lnz[0],
- &workFlags[0], NULL, NULL);
-
- if (optimizerVerbosenessLevel >= 1)
- cout << "SparseLevenbergOptimizer: Nonzeros in LDL decomposition: " << _JtJ_Lp[nColumns] << endl;
-
- } // end SparseLevenbergOptimizer::setupSparseJtJ()
-
- void
- SparseLevenbergOptimizer::serializeNonZerosJtJ(vector<pair<int, int> >& dst) const
- {
- int const nVaryingA = _nParametersA - _nNonvaryingA;
- int const nVaryingB = _nParametersB - _nNonvaryingB;
- int const nVaryingC = _paramDimensionC - _nNonvaryingC;
-
- int const bColumnStart = nVaryingA*_paramDimensionA;
- int const cColumnStart = bColumnStart + nVaryingB*_paramDimensionB;
-
- dst.clear();
-
- // Add the diagonal block matrices (only the upper triangular part).
-
- // Ui submatrices of JtJ
- for (int i = 0; i < nVaryingA; ++i)
- {
- int const i0 = i * _paramDimensionA;
-
- for (int c = 0; c < _paramDimensionA; ++c)
- for (int r = 0; r <= c; ++r)
- dst.push_back(make_pair(i0 + r, i0 + c));
- }
-
- // Vj submatrices of JtJ
- for (int j = 0; j < nVaryingB; ++j)
- {
- int const j0 = j*_paramDimensionB + bColumnStart;
-
- for (int c = 0; c < _paramDimensionB; ++c)
- for (int r = 0; r <= c; ++r)
- dst.push_back(make_pair(j0 + r, j0 + c));
- }
-
- // Z submatrix of JtJ
- for (int c = 0; c < nVaryingC; ++c)
- for (int r = 0; r <= c; ++r)
- dst.push_back(make_pair(cColumnStart + r, cColumnStart + c));
-
- // Add the elements i and j linked by an observation k
- // W submatrix of JtJ
- for (size_t n = 0; n < _jointNonzerosW.size(); ++n)
- {
- int const i0 = _jointNonzerosW[n].first;
- int const j0 = _jointNonzerosW[n].second;
- int const r0 = i0*_paramDimensionA;
- int const c0 = j0*_paramDimensionB + bColumnStart;
-
- for (int r = 0; r < _paramDimensionA; ++r)
- for (int c = 0; c < _paramDimensionB; ++c)
- dst.push_back(make_pair(r0 + r, c0 + c));
- } // end for (n)
-
- if (nVaryingC > 0)
- {
- // Finally, add the dense columns linking i (resp. j) with the global parameters.
- // X submatrix of JtJ
- for (int i = 0; i < nVaryingA; ++i)
- {
- int const i0 = i*_paramDimensionA;
-
- for (int r = 0; r < _paramDimensionA; ++r)
- for (int c = 0; c < nVaryingC; ++c)
- dst.push_back(make_pair(i0 + r, cColumnStart + c));
- }
-
- // Y submatrix of JtJ
- for (int j = 0; j < nVaryingB; ++j)
- {
- int const j0 = j*_paramDimensionB + bColumnStart;
-
- for (int r = 0; r < _paramDimensionB; ++r)
- for (int c = 0; c < nVaryingC; ++c)
- dst.push_back(make_pair(j0 + r, cColumnStart + c));
- }
- } // end if
- } // end SparseLevenbergOptimizer::serializeNonZerosJtJ()
-
- void
- SparseLevenbergOptimizer::fillSparseJtJ(MatrixArray<double> const& Ui,
- MatrixArray<double> const& Vj,
- MatrixArray<double> const& Wn,
- Matrix<double> const& Z,
- Matrix<double> const& X,
- Matrix<double> const& Y)
- {
- int const nVaryingA = _nParametersA - _nNonvaryingA;
- int const nVaryingB = _nParametersB - _nNonvaryingB;
- int const nVaryingC = _paramDimensionC - _nNonvaryingC;
-
- int const bColumnStart = nVaryingA*_paramDimensionA;
- int const cColumnStart = bColumnStart + nVaryingB*_paramDimensionB;
-
- int const nCols = _JtJ.num_cols();
- int const nnz = _JtJ.getNonzeroCount();
-
- // The following has to replicate the procedure as in serializeNonZerosJtJ()
-
- int serial = 0;
-
- double * values = _JtJ.getValues();
- int const * destIdxs = _JtJ.getDestIndices();
-
- // Add the diagonal block matrices (only the upper triangular part).
-
- // Ui submatrices of JtJ
- for (int i = 0; i < nVaryingA; ++i)
- {
- int const i0 = i * _paramDimensionA;
-
- for (int c = 0; c < _paramDimensionA; ++c)
- for (int r = 0; r <= c; ++r, ++serial)
- values[destIdxs[serial]] = Ui[i][r][c];
- }
-
- // Vj submatrices of JtJ
- for (int j = 0; j < nVaryingB; ++j)
- {
- int const j0 = j*_paramDimensionB + bColumnStart;
-
- for (int c = 0; c < _paramDimensionB; ++c)
- for (int r = 0; r <= c; ++r, ++serial)
- values[destIdxs[serial]] = Vj[j][r][c];
- }
-
- // Z submatrix of JtJ
- for (int c = 0; c < nVaryingC; ++c)
- for (int r = 0; r <= c; ++r, ++serial)
- values[destIdxs[serial]] = Z[r][c];
-
- // Add the elements i and j linked by an observation k
- // W submatrix of JtJ
- for (size_t n = 0; n < _jointNonzerosW.size(); ++n)
- {
- for (int r = 0; r < _paramDimensionA; ++r)
- for (int c = 0; c < _paramDimensionB; ++c, ++serial)
- values[destIdxs[serial]] = Wn[n][r][c];
- } // end for (k)
-
- if (nVaryingC > 0)
- {
- // Finally, add the dense columns linking i (resp. j) with the global parameters.
- // X submatrix of JtJ
- for (int i = 0; i < nVaryingA; ++i)
- {
- int const r0 = i * _paramDimensionA;
- for (int r = 0; r < _paramDimensionA; ++r)
- for (int c = 0; c < nVaryingC; ++c, ++serial)
- values[destIdxs[serial]] = X[r0+r][c];
- }
-
- // Y submatrix of JtJ
- for (int j = 0; j < nVaryingB; ++j)
- {
- int const r0 = j * _paramDimensionB;
- for (int r = 0; r < _paramDimensionB; ++r)
- for (int c = 0; c < nVaryingC; ++c, ++serial)
- values[destIdxs[serial]] = Y[r0+r][c];
- }
- } // end if
- } // end SparseLevenbergOptimizer::fillSparseJtJ()
-
- void
- SparseLevenbergOptimizer::minimize()
- {
- status = LEVENBERG_OPTIMIZER_TIMEOUT;
- bool computeDerivatives = true;
-
- int const nVaryingA = _nParametersA - _nNonvaryingA;
- int const nVaryingB = _nParametersB - _nNonvaryingB;
- int const nVaryingC = _paramDimensionC - _nNonvaryingC;
-
- if (nVaryingA == 0 && nVaryingB == 0 && nVaryingC == 0)
- {
- // No degrees of freedom, nothing to optimize.
- status = LEVENBERG_OPTIMIZER_CONVERGED;
- return;
- }
-
- this->setupSparseJtJ();
-
- Vector<double> weights(_nMeasurements);
-
- MatrixArray<double> Ak(_nMeasurements, _measurementDimension, _paramDimensionA);
- MatrixArray<double> Bk(_nMeasurements, _measurementDimension, _paramDimensionB);
- MatrixArray<double> Ck(_nMeasurements, _measurementDimension, _paramDimensionC);
-
- MatrixArray<double> Ui(nVaryingA, _paramDimensionA, _paramDimensionA);
- MatrixArray<double> Vj(nVaryingB, _paramDimensionB, _paramDimensionB);
-
- // Wn = Ak^t*Bk
- MatrixArray<double> Wn(_jointNonzerosW.size(), _paramDimensionA, _paramDimensionB);
-
- Matrix<double> Z(nVaryingC, nVaryingC);
-
- // X = A^t*C
- Matrix<double> X(nVaryingA*_paramDimensionA, nVaryingC);
- // Y = B^t*C
- Matrix<double> Y(nVaryingB*_paramDimensionB, nVaryingC);
-
- VectorArray<double> residuals(_nMeasurements, _measurementDimension);
- VectorArray<double> residuals2(_nMeasurements, _measurementDimension);
-
- VectorArray<double> diagUi(nVaryingA, _paramDimensionA);
- VectorArray<double> diagVj(nVaryingB, _paramDimensionB);
- Vector<double> diagZ(nVaryingC);
-
- VectorArray<double> At_e(nVaryingA, _paramDimensionA);
- VectorArray<double> Bt_e(nVaryingB, _paramDimensionB);
- Vector<double> Ct_e(nVaryingC);
-
- Vector<double> Jt_e(nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB + nVaryingC);
-
- Vector<double> delta(nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB + nVaryingC);
- Vector<double> deltaPerm(nVaryingA*_paramDimensionA + nVaryingB*_paramDimensionB + nVaryingC);
-
- VectorArray<double> deltaAi(_nParametersA, _paramDimensionA);
- VectorArray<double> deltaBj(_nParametersB, _paramDimensionB);
- Vector<double> deltaC(_paramDimensionC);
-
- double err = 0.0;
-
- for (currentIteration = 0; currentIteration < maxIterations; ++currentIteration)
- {
- if (optimizerVerbosenessLevel >= 2)
- cout << "SparseLevenbergOptimizer: currentIteration: " << currentIteration << endl;
- if (computeDerivatives)
- {
- this->evalResidual(residuals);
- this->fillWeights(residuals, weights);
- for (int k = 0; k < _nMeasurements; ++k)
- scaleVectorIP(weights[k], residuals[k]);
-
- err = squaredResidual(residuals);
-
- if (optimizerVerbosenessLevel >= 1) cout << "SparseLevenbergOptimizer: |residual|^2 = " << err << endl;
- if (optimizerVerbosenessLevel >= 2) cout << "SparseLevenbergOptimizer: lambda = " << lambda << endl;
-
- for (int k = 0; k < residuals.count(); ++k) scaleVectorIP(-1.0, residuals[k]);
-
- this->setupJacobianGathering();
- this->fillAllJacobians(weights, Ak, Bk, Ck);
-
- // Compute the different parts of J^t*e
- if (nVaryingA > 0)
- {
- for (int i = 0; i < nVaryingA; ++i) makeZeroVector(At_e[i]);
-
- Vector<double> tmp(_paramDimensionA);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- int const i = _correspondingParamA[k] - _nNonvaryingA;
- if (i < 0) continue;
- multiply_At_v(Ak[k], residuals[k], tmp);
- addVectors(tmp, At_e[i], At_e[i]);
- } // end for (k)
- } // end if
-
- if (nVaryingB > 0)
- {
- for (int j = 0; j < nVaryingB; ++j) makeZeroVector(Bt_e[j]);
-
- Vector<double> tmp(_paramDimensionB);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- int const j = _correspondingParamB[k] - _nNonvaryingB;
- if (j < 0) continue;
- multiply_At_v(Bk[k], residuals[k], tmp);
- addVectors(tmp, Bt_e[j], Bt_e[j]);
- } // end for (k)
- } // end if
-
- if (nVaryingC > 0)
- {
- makeZeroVector(Ct_e);
-
- Vector<double> tmp(_paramDimensionC);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- multiply_At_v(Ck[k], residuals[k], tmp);
- for (int l = 0; l < nVaryingC; ++l) Ct_e[l] += tmp[_nNonvaryingC + l];
- }
- } // end if
-
- int pos = 0;
- for (int i = 0; i < nVaryingA; ++i)
- for (int l = 0; l < _paramDimensionA; ++l, ++pos)
- Jt_e[pos] = At_e[i][l];
- for (int j = 0; j < nVaryingB; ++j)
- for (int l = 0; l < _paramDimensionB; ++l, ++pos)
- Jt_e[pos] = Bt_e[j][l];
- for (int l = 0; l < nVaryingC; ++l, ++pos)
- Jt_e[pos] = Ct_e[l];
-
-// cout << "Jt_e = ";
-// for (int k = 0; k < Jt_e.size(); ++k) cout << Jt_e[k] << " ";
-// cout << endl;
-
- if (this->applyGradientStoppingCriteria(norm_Linf(Jt_e)))
- {
- status = LEVENBERG_OPTIMIZER_CONVERGED;
- goto end;
- }
-
- // The lhs J^t*J consists of several parts:
- // [ U W X ]
- // J^t*J = [ W^t V Y ]
- // [ X^t Y^t Z ],
- // where U, V and W are block-sparse matrices (due to the sparsity of A and B).
- // X, Y and Z contain only a few columns (the number of global parameters).
-
- if (nVaryingA > 0)
- {
- // Compute Ui
- Matrix<double> U(_paramDimensionA, _paramDimensionA);
-
- for (int i = 0; i < nVaryingA; ++i) makeZeroMatrix(Ui[i]);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- int const i = _correspondingParamA[k] - _nNonvaryingA;
- if (i < 0) continue;
- multiply_At_A(Ak[k], U);
- addMatricesIP(U, Ui[i]);
- } // end for (k)
- } // end if
-
- if (nVaryingB > 0)
- {
- // Compute Vj
- Matrix<double> V(_paramDimensionB, _paramDimensionB);
-
- for (int j = 0; j < nVaryingB; ++j) makeZeroMatrix(Vj[j]);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- int const j = _correspondingParamB[k] - _nNonvaryingB;
- if (j < 0) continue;
- multiply_At_A(Bk[k], V);
- addMatricesIP(V, Vj[j]);
- } // end for (k)
- } // end if
-
- if (nVaryingC > 0)
- {
- Matrix<double> ZZ(_paramDimensionC, _paramDimensionC);
- Matrix<double> Zsum(_paramDimensionC, _paramDimensionC);
-
- makeZeroMatrix(Zsum);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- multiply_At_A(Ck[k], ZZ);
- addMatricesIP(ZZ, Zsum);
- } // end for (k)
-
- // Ignore the non-varying parameters
- for (int i = 0; i < nVaryingC; ++i)
- for (int j = 0; j < nVaryingC; ++j)
- Z[i][j] = Zsum[i+_nNonvaryingC][j+_nNonvaryingC];
- } // end if
-
- if (nVaryingA > 0 && nVaryingB > 0)
- {
- for (int n = 0; n < Wn.count(); ++n) makeZeroMatrix(Wn[n]);
-
- Matrix<double> W(_paramDimensionA, _paramDimensionB);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- int const n = _jointIndexW[k];
- if (n >= 0)
- {
- int const i0 = _jointNonzerosW[n].first;
- int const j0 = _jointNonzerosW[n].second;
-
- multiply_At_B(Ak[k], Bk[k], W);
- addMatricesIP(W, Wn[n]);
- } // end if
- } // end for (k)
- } // end if
-
- if (nVaryingA > 0 && nVaryingC > 0)
- {
- Matrix<double> XX(_paramDimensionA, _paramDimensionC);
-
- makeZeroMatrix(X);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- int const i = _correspondingParamA[k] - _nNonvaryingA;
- // Ignore the non-varying parameters
- if (i < 0) continue;
-
- multiply_At_B(Ak[k], Ck[k], XX);
-
- for (int r = 0; r < _paramDimensionA; ++r)
- for (int c = 0; c < nVaryingC; ++c)
- X[r+i*_paramDimensionA][c] += XX[r][c+_nNonvaryingC];
- } // end for (k)
- } // end if
-
- if (nVaryingB > 0 && nVaryingC > 0)
- {
- Matrix<double> YY(_paramDimensionB, _paramDimensionC);
-
- makeZeroMatrix(Y);
-
- for (int k = 0; k < _nMeasurements; ++k)
- {
- int const j = _correspondingParamB[k] - _nNonvaryingB;
- // Ignore the non-varying parameters
- if (j < 0) continue;
-
- multiply_At_B(Bk[k], Ck[k], YY);
-
- for (int r = 0; r < _paramDimensionB; ++r)
- for (int c = 0; c < nVaryingC; ++c)
- Y[r+j*_paramDimensionB][c] += YY[r][c+_nNonvaryingC];
- } // end for (k)
- } // end if
-
- if (currentIteration == 0)
- {
- // Initialize lambda as tau*max(JtJ[i][i])
- double maxEl = -1e30;
- if (nVaryingA > 0)
- {
- for (int i = 0; i < nVaryingA; ++i)
- for (int l = 0; l < _paramDimensionA; ++l)
- maxEl = std::max(maxEl, Ui[i][l][l]);
- }
- if (nVaryingB > 0)
- {
- for (int j = 0; j < nVaryingB; ++j)
- for (int l = 0; l < _paramDimensionB; ++l)
- maxEl = std::max(maxEl, Vj[j][l][l]);
- }
- if (nVaryingC > 0)
- {
- for (int l = 0; l < nVaryingC; ++l)
- maxEl = std::max(maxEl, Z[l][l]);
- }
-
- lambda = tau * maxEl;
- if (optimizerVerbosenessLevel >= 2)
- cout << "SparseLevenbergOptimizer: initial lambda = " << lambda << endl;
- } // end if (currentIteration == 0)
- } // end if (computeDerivatives)
-
- for (int i = 0; i < nVaryingA; ++i)
- {
- for (int l = 0; l < _paramDimensionA; ++l) diagUi[i][l] = Ui[i][l][l];
- } // end for (i)
-
- for (int j = 0; j < nVaryingB; ++j)
- {
- for (int l = 0; l < _paramDimensionB; ++l) diagVj[j][l] = Vj[j][l][l];
- } // end for (j)
-
- for (int l = 0; l < nVaryingC; ++l) diagZ[l] = Z[l][l];
-
- // Augment the diagonals with lambda (either by the standard additive update or by multiplication).
-#if !defined(USE_MULTIPLICATIVE_UPDATE)
- for (int i = 0; i < nVaryingA; ++i)
- for (unsigned l = 0; l < _paramDimensionA; ++l)
- Ui[i][l][l] += lambda;
-
- for (int j = 0; j < nVaryingB; ++j)
- for (unsigned l = 0; l < _paramDimensionB; ++l)
- Vj[j][l][l] += lambda;
-
- for (unsigned l = 0; l < nVaryingC; ++l)
- Z[l][l] += lambda;
-#else
- for (int i = 0; i < nVaryingA; ++i)
- for (unsigned l = 0; l < _paramDimensionA; ++l)
- Ui[i][l][l] = std::max(Ui[i][l][l] * (1.0 + lambda), 1e-15);
-
- for (int j = 0; j < nVaryingB; ++j)
- for (unsigned l = 0; l < _paramDimensionB; ++l)
- Vj[j][l][l] = std::max(Vj[j][l][l] * (1.0 + lambda), 1e-15);
-
- for (unsigned l = 0; l < nVaryingC; ++l)
- Z[l][l] = std::max(Z[l][l] * (1.0 + lambda), 1e-15);
-#endif
-
- this->fillSparseJtJ(Ui, Vj, Wn, Z, X, Y);
-
- bool success = true;
- double rho = 0.0;
- {
- int const nCols = _JtJ_Parent.size();
- int const nnz = _JtJ.getNonzeroCount();
- int const lnz = _JtJ_Lp.back();
-
- vector<int> Li(lnz);
- vector<double> Lx(lnz);
- vector<double> D(nCols), Y(nCols);
- vector<int> workPattern(nCols), workFlag(nCols);
-
- int * colStarts = (int *)_JtJ.getColumnStarts();
- int * rowIdxs = (int *)_JtJ.getRowIndices();
- double * values = _JtJ.getValues();
-
- int const d = ldl_numeric(nCols, colStarts, rowIdxs, values,
- &_JtJ_Lp[0], &_JtJ_Parent[0], &_JtJ_Lnz[0],
- &Li[0], &Lx[0], &D[0],
- &Y[0], &workPattern[0], &workFlag[0],
- NULL, NULL);
-
- if (d == nCols)
- {
- ldl_perm(nCols, &deltaPerm[0], &Jt_e[0], &_perm_JtJ[0]);
- ldl_lsolve(nCols, &deltaPerm[0], &_JtJ_Lp[0], &Li[0], &Lx[0]);
- ldl_dsolve(nCols, &deltaPerm[0], &D[0]);
- ldl_ltsolve(nCols, &deltaPerm[0], &_JtJ_Lp[0], &Li[0], &Lx[0]);
- ldl_permt(nCols, &delta[0], &deltaPerm[0], &_perm_JtJ[0]);
- }
- else
- {
- if (optimizerVerbosenessLevel >= 2)
- cout << "SparseLevenbergOptimizer: LDL decomposition failed. Increasing lambda." << endl;
- success = false;
- }
- }
-
- if (success)
- {
- double const deltaSqrLength = sqrNorm_L2(delta);
-
- if (optimizerVerbosenessLevel >= 2)
- cout << "SparseLevenbergOptimizer: ||delta||^2 = " << deltaSqrLength << endl;
-
- double const paramLength = this->getParameterLength();
- if (this->applyUpdateStoppingCriteria(paramLength, sqrt(deltaSqrLength)))
- {
- status = LEVENBERG_OPTIMIZER_SMALL_UPDATE;
- goto end;
- }
-
- // Copy the updates from delta to the respective arrays
- int pos = 0;
-
- for (int i = 0; i < _nNonvaryingA; ++i) makeZeroVector(deltaAi[i]);
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- for (int l = 0; l < _paramDimensionA; ++l, ++pos)
- deltaAi[i][l] = delta[pos];
-
- for (int j = 0; j < _nNonvaryingB; ++j) makeZeroVector(deltaBj[j]);
- for (int j = _nNonvaryingB; j < _nParametersB; ++j)
- for (int l = 0; l < _paramDimensionB; ++l, ++pos)
- deltaBj[j][l] = delta[pos];
-
- makeZeroVector(deltaC);
- for (int l = _nNonvaryingC; l < _paramDimensionC; ++l, ++pos)
- deltaC[l] = delta[pos];
-
- saveAllParameters();
- if (nVaryingA > 0) updateParametersA(deltaAi);
- if (nVaryingB > 0) updateParametersB(deltaBj);
- if (nVaryingC > 0) updateParametersC(deltaC);
-
- this->evalResidual(residuals2);
- for (int k = 0; k < _nMeasurements; ++k)
- scaleVectorIP(weights[k], residuals2[k]);
-
- double const newErr = squaredResidual(residuals2);
- rho = err - newErr;
- if (optimizerVerbosenessLevel >= 2)
- cout << "SparseLevenbergOptimizer: |new residual|^2 = " << newErr << endl;
-
-#if !defined(USE_MULTIPLICATIVE_UPDATE)
- double const denom1 = lambda * deltaSqrLength;
-#else
- double denom1 = 0.0f;
- for (int i = _nNonvaryingA; i < _nParametersA; ++i)
- for (int l = 0; l < _paramDimensionA; ++l)
- denom1 += deltaAi[i][l] * deltaAi[i][l] * diagUi[i-_nNonvaryingA][l];
-
- for (int j = _nNonvaryingB; j < _nParametersB; ++j)
- for (int l = 0; l < _paramDimensionB; ++l)
- denom1 += deltaBj[j][l] * deltaBj[j][l] * diagVj[j-_nNonvaryingB][l];
-
- for (int l = _nNonvaryingC; l < _paramDimensionC; ++l)
- denom1 += deltaC[l] * deltaC[l] * diagZ[l-_nNonvaryingC];
-
- denom1 *= lambda;
-#endif
- double const denom2 = innerProduct(delta, Jt_e);
- rho = rho / (denom1 + denom2);
- if (optimizerVerbosenessLevel >= 2)
- cout << "SparseLevenbergOptimizer: rho = " << rho
- << " denom1 = " << denom1 << " denom2 = " << denom2 << endl;
- } // end if (success)
-
- if (success && rho > 0)
- {
- if (optimizerVerbosenessLevel >= 2)
- cout << "SparseLevenbergOptimizer: Improved solution - decreasing lambda." << endl;
- // Improvement in the new solution
- decreaseLambda(rho);
- computeDerivatives = true;
- }
- else
- {
- if (optimizerVerbosenessLevel >= 2)
- cout << "SparseLevenbergOptimizer: Inferior solution - increasing lambda." << endl;
- restoreAllParameters();
- increaseLambda();
- computeDerivatives = false;
-
- // Restore diagonal elements in Ui, Vj and Z.
- for (int i = 0; i < nVaryingA; ++i)
- {
- for (int l = 0; l < _paramDimensionA; ++l) Ui[i][l][l] = diagUi[i][l];
- } // end for (i)
-
- for (int j = 0; j < nVaryingB; ++j)
- {
- for (int l = 0; l < _paramDimensionB; ++l) Vj[j][l][l] = diagVj[j][l];
- } // end for (j)
-
- for (int l = 0; l < nVaryingC; ++l) Z[l][l] = diagZ[l];
- } // end if
- } // end for
-
- end:;
- if (optimizerVerbosenessLevel >= 2)
- cout << "Leaving SparseLevenbergOptimizer::minimize()." << endl;
- } // end SparseLevenbergOptimizer::minimize()
-
-#endif // defined(V3DLIB_ENABLE_SUITESPARSE)
-
-} // end namespace V3D
diff --git a/extern/libmv/third_party/ssba/Math/v3d_optimization.h b/extern/libmv/third_party/ssba/Math/v3d_optimization.h
deleted file mode 100644
index 27d2e12287f..00000000000
--- a/extern/libmv/third_party/ssba/Math/v3d_optimization.h
+++ /dev/null
@@ -1,273 +0,0 @@
-// -*- C++ -*-
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA 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.
-
-SSBA is distributed in the hope that 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 SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef V3D_OPTIMIZATION_H
-#define V3D_OPTIMIZATION_H
-
-#include "Math/v3d_linear.h"
-#include "Math/v3d_mathutilities.h"
-
-#include <vector>
-#include <iostream>
-
-namespace V3D
-{
-
- enum
- {
- LEVENBERG_OPTIMIZER_TIMEOUT = 0,
- LEVENBERG_OPTIMIZER_SMALL_UPDATE = 1,
- LEVENBERG_OPTIMIZER_CONVERGED = 2
- };
-
- extern int optimizerVerbosenessLevel;
-
- struct LevenbergOptimizerCommon
- {
- LevenbergOptimizerCommon()
- : status(LEVENBERG_OPTIMIZER_TIMEOUT), currentIteration(0), maxIterations(50),
- tau(1e-3), lambda(1e-3),
- gradientThreshold(1e-10), updateThreshold(1e-10),
- _nu(2.0)
- { }
- virtual ~LevenbergOptimizerCommon() {}
-
- // See Madsen et al., "Methods for non-linear least squares problems."
- virtual void increaseLambda()
- {
- lambda *= _nu; _nu *= 2.0;
- }
-
- virtual void decreaseLambda(double const rho)
- {
- double const r = 2*rho - 1.0;
- lambda *= std::max(1.0/3.0, 1 - r*r*r);
- if (lambda < 1e-10) lambda = 1e-10;
- _nu = 2;
- }
-
- bool applyGradientStoppingCriteria(double maxGradient) const
- {
- return maxGradient < gradientThreshold;
- }
-
- bool applyUpdateStoppingCriteria(double paramLength, double updateLength) const
- {
- return updateLength < updateThreshold * (paramLength + updateThreshold);
- }
-
- int status;
- int currentIteration, maxIterations;
- double tau, lambda;
- double gradientThreshold, updateThreshold;
-
- protected:
- double _nu;
- }; // end struct LevenbergOptimizerCommon
-
-# if defined(V3DLIB_ENABLE_SUITESPARSE)
-
- struct SparseLevenbergOptimizer : public LevenbergOptimizerCommon
- {
- SparseLevenbergOptimizer(int measurementDimension,
- int nParametersA, int paramDimensionA,
- int nParametersB, int paramDimensionB,
- int paramDimensionC,
- std::vector<int> const& correspondingParamA,
- std::vector<int> const& correspondingParamB)
- : LevenbergOptimizerCommon(),
- _nMeasurements(correspondingParamA.size()),
- _measurementDimension(measurementDimension),
- _nParametersA(nParametersA), _paramDimensionA(paramDimensionA),
- _nParametersB(nParametersB), _paramDimensionB(paramDimensionB),
- _paramDimensionC(paramDimensionC),
- _nNonvaryingA(0), _nNonvaryingB(0), _nNonvaryingC(0),
- _correspondingParamA(correspondingParamA),
- _correspondingParamB(correspondingParamB)
- {
- assert(correspondingParamA.size() == correspondingParamB.size());
- }
-
- ~SparseLevenbergOptimizer() { }
-
- void setNonvaryingCounts(int nNonvaryingA, int nNonvaryingB, int nNonvaryingC)
- {
- _nNonvaryingA = nNonvaryingA;
- _nNonvaryingB = nNonvaryingB;
- _nNonvaryingC = nNonvaryingC;
- }
-
- void getNonvaryingCounts(int& nNonvaryingA, int& nNonvaryingB, int& nNonvaryingC) const
- {
- nNonvaryingA = _nNonvaryingA;
- nNonvaryingB = _nNonvaryingB;
- nNonvaryingC = _nNonvaryingC;
- }
-
- void minimize();
-
- virtual void evalResidual(VectorArray<double>& residuals) = 0;
-
- virtual void fillWeights(VectorArray<double> const& residuals, Vector<double>& w)
- {
- (void)residuals;
- std::fill(w.begin(), w.end(), 1.0);
- }
-
- void fillAllJacobians(Vector<double> const& w,
- MatrixArray<double>& Ak,
- MatrixArray<double>& Bk,
- MatrixArray<double>& Ck)
- {
- int const nVaryingA = _nParametersA - _nNonvaryingA;
- int const nVaryingB = _nParametersB - _nNonvaryingB;
- int const nVaryingC = _paramDimensionC - _nNonvaryingC;
-
- for (unsigned k = 0; k < _nMeasurements; ++k)
- {
- int const i = _correspondingParamA[k];
- int const j = _correspondingParamB[k];
-
- if (i < _nNonvaryingA && j < _nNonvaryingB) continue;
-
- fillJacobians(Ak[k], Bk[k], Ck[k], i, j, k);
- } // end for (k)
-
- if (nVaryingA > 0)
- {
- for (unsigned k = 0; k < _nMeasurements; ++k)
- scaleMatrixIP(w[k], Ak[k]);
- }
- if (nVaryingB > 0)
- {
- for (unsigned k = 0; k < _nMeasurements; ++k)
- scaleMatrixIP(w[k], Bk[k]);
- }
- if (nVaryingC > 0)
- {
- for (unsigned k = 0; k < _nMeasurements; ++k)
- scaleMatrixIP(w[k], Ck[k]);
- }
- } // end fillAllJacobians()
-
- virtual void setupJacobianGathering() { }
-
- virtual void fillJacobians(Matrix<double>& Ak, Matrix<double>& Bk, Matrix<double>& Ck,
- int i, int j, int k) = 0;
-
- virtual double getParameterLength() const = 0;
-
- virtual void updateParametersA(VectorArray<double> const& deltaAi) = 0;
- virtual void updateParametersB(VectorArray<double> const& deltaBj) = 0;
- virtual void updateParametersC(Vector<double> const& deltaC) = 0;
- virtual void saveAllParameters() = 0;
- virtual void restoreAllParameters() = 0;
-
- int currentIteration, maxIterations;
-
- protected:
- void serializeNonZerosJtJ(std::vector<std::pair<int, int> >& dst) const;
- void setupSparseJtJ();
- void fillSparseJtJ(MatrixArray<double> const& Ui, MatrixArray<double> const& Vj, MatrixArray<double> const& Wk,
- Matrix<double> const& Z, Matrix<double> const& X, Matrix<double> const& Y);
-
- int const _nMeasurements, _measurementDimension;
- int const _nParametersA, _paramDimensionA;
- int const _nParametersB, _paramDimensionB;
- int const _paramDimensionC;
-
- int _nNonvaryingA, _nNonvaryingB, _nNonvaryingC;
-
- std::vector<int> const& _correspondingParamA;
- std::vector<int> const& _correspondingParamB;
-
- std::vector<pair<int, int> > _jointNonzerosW;
- std::vector<int> _jointIndexW;
-
- std::vector<int> _JtJ_Lp, _JtJ_Parent, _JtJ_Lnz;
- std::vector<int> _perm_JtJ, _invPerm_JtJ;
-
- CCS_Matrix<double> _JtJ;
- }; // end struct SparseLevenbergOptimizer
-
- struct StdSparseLevenbergOptimizer : public SparseLevenbergOptimizer
- {
- StdSparseLevenbergOptimizer(int measurementDimension,
- int nParametersA, int paramDimensionA,
- int nParametersB, int paramDimensionB,
- int paramDimensionC,
- std::vector<int> const& correspondingParamA,
- std::vector<int> const& correspondingParamB)
- : SparseLevenbergOptimizer(measurementDimension, nParametersA, paramDimensionA,
- nParametersB, paramDimensionB, paramDimensionC,
- correspondingParamA, correspondingParamB),
- curParametersA(nParametersA, paramDimensionA), savedParametersA(nParametersA, paramDimensionA),
- curParametersB(nParametersB, paramDimensionB), savedParametersB(nParametersB, paramDimensionB),
- curParametersC(paramDimensionC), savedParametersC(paramDimensionC)
- { }
-
- virtual double getParameterLength() const
- {
- double res = 0.0;
- for (int i = 0; i < _nParametersA; ++i) res += sqrNorm_L2(curParametersA[i]);
- for (int j = 0; j < _nParametersB; ++j) res += sqrNorm_L2(curParametersB[j]);
- res += sqrNorm_L2(curParametersC);
- return sqrt(res);
- }
-
- virtual void updateParametersA(VectorArray<double> const& deltaAi)
- {
- for (int i = 0; i < _nParametersA; ++i) addVectors(deltaAi[i], curParametersA[i], curParametersA[i]);
- }
-
- virtual void updateParametersB(VectorArray<double> const& deltaBj)
- {
- for (int j = 0; j < _nParametersB; ++j) addVectors(deltaBj[j], curParametersB[j], curParametersB[j]);
- }
-
- virtual void updateParametersC(Vector<double> const& deltaC)
- {
- addVectors(deltaC, curParametersC, curParametersC);
- }
-
- virtual void saveAllParameters()
- {
- for (int i = 0; i < _nParametersA; ++i) savedParametersA[i] = curParametersA[i];
- for (int j = 0; j < _nParametersB; ++j) savedParametersB[j] = curParametersB[j];
- savedParametersC = curParametersC;
- }
-
- virtual void restoreAllParameters()
- {
- for (int i = 0; i < _nParametersA; ++i) curParametersA[i] = savedParametersA[i];
- for (int j = 0; j < _nParametersB; ++j) curParametersB[j] = savedParametersB[j];
- curParametersC = savedParametersC;
- }
-
- VectorArray<double> curParametersA, savedParametersA;
- VectorArray<double> curParametersB, savedParametersB;
- Vector<double> curParametersC, savedParametersC;
- }; // end struct StdSparseLevenbergOptimizer
-
-# endif
-
-} // end namespace V3D
-
-#endif
diff --git a/extern/libmv/third_party/ssba/README.TXT b/extern/libmv/third_party/ssba/README.TXT
deleted file mode 100644
index 734962b1df8..00000000000
--- a/extern/libmv/third_party/ssba/README.TXT
+++ /dev/null
@@ -1,92 +0,0 @@
-Description
-
-This is an implementation of a sparse Levenberg-Marquardt optimization
-procedure and several bundle adjustment modules based on it. There are three
-versions of bundle adjustment:
-1) Pure metric adjustment. Camera poses have 6 dof and 3D points have 3 dof.
-2) Common, but adjustable intrinsic and distortion parameters. This is useful,
- if the set of images are taken with the same camera under constant zoom
- settings.
-3) Variable intrinsics and distortion parameters for each view. This addresses
- the "community photo collection" setting, where each image is captured with
- a different camera and/or with varying zoom setting.
-
-There are two demo applications in the Apps directory, bundle_common and
-bundle_varying, which correspond to item 2) and 3) above.
-
-The input data file for both applications is a text file with the following
-numerical values:
-
-First, the number of 3D points, views and 2D measurements:
-<M> <N> <K>
-Then, the values of the intrinsic matrix
- [ fx skew cx ]
-K = [ 0 fy cy ]
- [ 0 0 1 ],
-and the distortion parameters according to the convention of the Bouget
-toolbox:
-
- <fx> <skew> <cx> <fy> <cy> <k1> <k2> <p1> <p2>
-
-For the bundle_varying application this is given <N> times, one for each
-camera/view.
-Then the <M> 3D point positions are given:
-
- <point-id> <X> <Y> <Z>
-
-Note: the point-ids need not to be exactly from 0 to M-1, any (unique) ids
-will do.
-The camera poses are given subsequently:
-
- <view-id> <12 entries of the RT matrix>
-
-There is a lot of confusion how to specify the orientation of cameras. We use
-projection matrix notation, i.e. P = K [R|T], and a 3D point X in world
-coordinates is transformed into the camera coordinate system by XX=R*X+T.
-
-Finally, the <K> 2d image measurements (given in pixels) are provided:
-
- <view-id> <point-id> <x> <y> 1
-
-See the example in the Dataset folder.
-
-
-Performance
-
-This software is able to perform successful loop closing for a video sequence
-containing 1745 views, 37920 3D points and 627228 image measurements in about
-16min on a 2.2 GHz Core 2. The footprint in memory was <700MB.
-
-
-Requirements
-
-Solving the augmented normal equation in the LM optimizer is done with LDL, a
-Cholsky like decomposition method for sparse matrices (see
-http://www.cise.ufl.edu/research/sparse/ldl). The appropriate column
-reordering is done with COLAMD (see
-http://www.cise.ufl.edu/research/sparse/colamd). Both packages are licensed
-under the GNU LGPL.
-
-This software was developed under Linux, but should compile equally well on
-other operating systems.
-
--Christopher Zach (cmzach@cs.unc.edu)
-
-/*
-Copyright (c) 2008 University of North Carolina at Chapel Hill
-
-This file is part of SSBA (Simple Sparse Bundle Adjustment).
-
-SSBA 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.
-
-SSBA is distributed in the hope that 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 SSBA. If not, see <http://www.gnu.org/licenses/>.
-*/
diff --git a/extern/libmv/third_party/ssba/README.libmv b/extern/libmv/third_party/ssba/README.libmv
deleted file mode 100644
index 45e0a31f6fc..00000000000
--- a/extern/libmv/third_party/ssba/README.libmv
+++ /dev/null
@@ -1,23 +0,0 @@
-Project: SSBA
-URL: http://www.cs.unc.edu/~cmzach/opensource.html
-License: LGPL3
-Upstream version: 1.0
-
-Local modifications:
-
- * Added
- SET(CMAKE_CXX_FLAGS "")
- to CMakeLists.txt to prevent warnings from being treated as errors.
- * Fixed "unused variable" in the header files. Warnings in the cpps files
- are still there.
- * Fixed a bug in CameraMatrix::opticalAxis() in file
- Geometry/v3d_cameramatrix.h
- * Deleted the Dataset directory.
- * Added '#include <string>' to ssba/Apps/bundle_common.cpp and
- ssba/Apps/bundle_varying.cpp to stop undefined references to strcmp
- * Removed unnecessary elements from the CMakeLists.txt file, including the
- obsoleted local_config.cmake and friends.
- * Added a virtual destructor to V3D::LevenbergOptimizerCommon in
- Math/v3d_optimization.h
- * Added /EHsc WIN32-specific flag to CMakeLists.txt
- * Remove unused variable Vector3d np in bundle_common.cpp and bundle_varying (in main() function).
diff --git a/extern/lzo/minilzo/COPYING b/extern/lzo/minilzo/COPYING
index 5ee49f42e91..d159169d105 100644
--- a/extern/lzo/minilzo/COPYING
+++ b/extern/lzo/minilzo/COPYING
@@ -1,8 +1,8 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, 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.
@@ -15,7 +15,7 @@ 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
+the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
@@ -55,7 +55,7 @@ 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
@@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
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
@@ -168,7 +168,7 @@ 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
@@ -225,7 +225,7 @@ 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
@@ -278,7 +278,7 @@ 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
@@ -291,7 +291,7 @@ 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>
+ 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
@@ -303,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- You 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
-
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 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.
@@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names:
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
+library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
diff --git a/extern/lzo/minilzo/README.LZO b/extern/lzo/minilzo/README.LZO
index 3700f28e310..058eace70a0 100644
--- a/extern/lzo/minilzo/README.LZO
+++ b/extern/lzo/minilzo/README.LZO
@@ -6,8 +6,8 @@
Author : Markus Franz Xaver Johannes Oberhumer
<markus@oberhumer.com>
http://www.oberhumer.com/opensource/lzo/
- Version : 2.03
- Date : 30 Apr 2008
+ Version : 2.06
+ Date : 12 Aug 2011
I've created miniLZO for projects where it is inconvenient to
include (or require) the full LZO source code just because you
@@ -24,10 +24,10 @@
To use miniLZO just copy these files into your source directory, add
minilzo.c to your Makefile and #include minilzo.h from your program.
- Note: you also must distribute this file (`README.LZO') with your project.
+ Note: you also must distribute this file ('README.LZO') with your project.
- minilzo.o compiles to about 6 kB (using gcc or Visual C on a i386), and
- the sources are about 30 kB when packed with zip - so there's no more
+ minilzo.o compiles to about 6 KiB (using gcc or Visual C on an i386), and
+ the sources are about 30 KiB when packed with zip - so there's no more
excuse that your application doesn't support data compression :-)
For more information, documentation, example programs and other support
@@ -49,15 +49,15 @@
out-of-the-box on most machines.
If you are running on a very unusual architecture and lzo_init() fails then
- you should first recompile with `-DLZO_DEBUG' to see what causes the failure.
- The most probable case is something like `sizeof(char *) != sizeof(long)'.
+ you should first recompile with '-DLZO_DEBUG' to see what causes the failure.
+ The most probable case is something like 'sizeof(void *) != sizeof(size_t)'.
After identifying the problem you can compile by adding some defines
- like `-DSIZEOF_CHAR_P=8' to your Makefile.
+ like '-DSIZEOF_VOID_P=8' to your Makefile.
The best solution is (of course) using Autoconf - if your project uses
- Autoconf anyway just add `-DMINILZO_HAVE_CONFIG_H' to your compiler
+ Autoconf anyway just add '-DMINILZO_HAVE_CONFIG_H' to your compiler
flags when compiling minilzo.c. See the LZO distribution for an example
- how to set up configure.in.
+ how to set up configure.ac.
Appendix B: list of public functions available in miniLZO
@@ -87,7 +87,7 @@
lzo_memset()
- Appendix C: suggested macros for `configure.in' when using Autoconf
+ Appendix C: suggested macros for 'configure.ac' when using Autoconf
-------------------------------------------------------------------
Checks for typedefs and structures
AC_CHECK_TYPE(ptrdiff_t,long)
@@ -110,8 +110,9 @@
Appendix D: Copyright
---------------------
- LZO and miniLZO are Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008 Markus Franz Xaver Johannes Oberhumer
+ LZO and miniLZO are Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001,
+ 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ Markus Franz Xaver Oberhumer <markus@oberhumer.com>.
LZO and miniLZO are distributed under the terms of the GNU General
Public License (GPL). See the file COPYING.
diff --git a/extern/lzo/minilzo/lzoconf.h b/extern/lzo/minilzo/lzoconf.h
index cc437f1ebfe..23c6ca93fcc 100644
--- a/extern/lzo/minilzo/lzoconf.h
+++ b/extern/lzo/minilzo/lzoconf.h
@@ -1,7 +1,10 @@
-/* lzoconf.h -- configuration for the LZO real-time data compression library
+/* lzoconf.h -- configuration of the LZO data compression library
This file is part of the LZO real-time data compression library.
+ Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
@@ -39,11 +42,11 @@
#ifndef __LZOCONF_H_INCLUDED
-#define __LZOCONF_H_INCLUDED
+#define __LZOCONF_H_INCLUDED 1
-#define LZO_VERSION 0x2030
-#define LZO_VERSION_STRING "2.03"
-#define LZO_VERSION_DATE "Apr 30 2008"
+#define LZO_VERSION 0x2060
+#define LZO_VERSION_STRING "2.06"
+#define LZO_VERSION_DATE "Aug 12 2011"
/* internal Autoconf configuration file - only used when building LZO */
#if defined(LZO_HAVE_CONFIG_H)
@@ -157,6 +160,27 @@ extern "C" {
# endif
#endif
+/* Integral types with exactly 64 bits. */
+#if !defined(LZO_UINT64_MAX)
+# if (LZO_UINT_MAX >= LZO_0xffffffffL)
+# if ((((LZO_UINT_MAX) >> 31) >> 31) == 3)
+# define lzo_uint64 lzo_uint
+# define lzo_int64 lzo_int
+# define LZO_UINT64_MAX LZO_UINT_MAX
+# define LZO_INT64_MAX LZO_INT_MAX
+# define LZO_INT64_MIN LZO_INT_MIN
+# endif
+# elif (ULONG_MAX >= LZO_0xffffffffL)
+# if ((((ULONG_MAX) >> 31) >> 31) == 3)
+ typedef unsigned long lzo_uint64;
+ typedef long lzo_int64;
+# define LZO_UINT64_MAX ULONG_MAX
+# define LZO_INT64_MAX LONG_MAX
+# define LZO_INT64_MIN LONG_MIN
+# endif
+# endif
+#endif
+
/* The larger type of lzo_uint and lzo_uint32. */
#if (LZO_UINT_MAX >= LZO_UINT32_MAX)
# define lzo_xint lzo_uint
@@ -167,12 +191,12 @@ extern "C" {
/* Memory model that allows to access memory at offsets of lzo_uint. */
#if !defined(__LZO_MMODEL)
# if (LZO_UINT_MAX <= UINT_MAX)
-# define __LZO_MMODEL
+# define __LZO_MMODEL /*empty*/
# elif defined(LZO_HAVE_MM_HUGE_PTR)
# define __LZO_MMODEL_HUGE 1
# define __LZO_MMODEL __huge
# else
-# define __LZO_MMODEL
+# define __LZO_MMODEL /*empty*/
# endif
#endif
@@ -184,12 +208,16 @@ extern "C" {
#define lzo_ushortp unsigned short __LZO_MMODEL *
#define lzo_uint32p lzo_uint32 __LZO_MMODEL *
#define lzo_int32p lzo_int32 __LZO_MMODEL *
+#if defined(LZO_UINT64_MAX)
+#define lzo_uint64p lzo_uint64 __LZO_MMODEL *
+#define lzo_int64p lzo_int64 __LZO_MMODEL *
+#endif
#define lzo_uintp lzo_uint __LZO_MMODEL *
#define lzo_intp lzo_int __LZO_MMODEL *
#define lzo_xintp lzo_xint __LZO_MMODEL *
#define lzo_voidpp lzo_voidp __LZO_MMODEL *
#define lzo_bytepp lzo_bytep __LZO_MMODEL *
-/* deprecated - use `lzo_bytep' instead of `lzo_byte *' */
+/* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */
#define lzo_byte unsigned char __LZO_MMODEL
typedef int lzo_bool;
@@ -215,10 +243,10 @@ typedef int lzo_bool;
/* DLL export information */
#if !defined(__LZO_EXPORT1)
-# define __LZO_EXPORT1
+# define __LZO_EXPORT1 /*empty*/
#endif
#if !defined(__LZO_EXPORT2)
-# define __LZO_EXPORT2
+# define __LZO_EXPORT2 /*empty*/
#endif
/* __cdecl calling convention for public C and assembly functions */
@@ -306,7 +334,7 @@ struct lzo_callback_t
*/
#define LZO_E_OK 0
#define LZO_E_ERROR (-1)
-#define LZO_E_OUT_OF_MEMORY (-2) /* [not used right now] */
+#define LZO_E_OUT_OF_MEMORY (-2) /* [lzo_alloc_func_t failure] */
#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */
#define LZO_E_INPUT_OVERRUN (-4)
#define LZO_E_OUTPUT_OVERRUN (-5)
@@ -314,6 +342,7 @@ struct lzo_callback_t
#define LZO_E_EOF_NOT_FOUND (-7)
#define LZO_E_INPUT_NOT_CONSUMED (-8)
#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */
+#define LZO_E_INVALID_ARGUMENT (-10)
#ifndef lzo_sizeof_dict_t
@@ -341,32 +370,32 @@ LZO_EXTERN(const lzo_charp) _lzo_version_date(void);
/* string functions */
LZO_EXTERN(int)
-lzo_memcmp(const lzo_voidp _s1, const lzo_voidp _s2, lzo_uint _len);
+ lzo_memcmp(const lzo_voidp a, const lzo_voidp b, lzo_uint len);
LZO_EXTERN(lzo_voidp)
-lzo_memcpy(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
+ lzo_memcpy(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
LZO_EXTERN(lzo_voidp)
-lzo_memmove(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
+ lzo_memmove(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
LZO_EXTERN(lzo_voidp)
-lzo_memset(lzo_voidp _s, int _c, lzo_uint _len);
+ lzo_memset(lzo_voidp buf, int c, lzo_uint len);
/* checksum functions */
LZO_EXTERN(lzo_uint32)
-lzo_adler32(lzo_uint32 _adler, const lzo_bytep _buf, lzo_uint _len);
+ lzo_adler32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len);
LZO_EXTERN(lzo_uint32)
-lzo_crc32(lzo_uint32 _c, const lzo_bytep _buf, lzo_uint _len);
+ lzo_crc32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len);
LZO_EXTERN(const lzo_uint32p)
-lzo_get_crc32_table(void);
+ lzo_get_crc32_table(void);
/* misc. */
LZO_EXTERN(int) _lzo_config_check(void);
typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u;
typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u;
-typedef union { void *vp; lzo_bytep bp; lzo_uint32 u32; long l; } lzo_align_t;
+typedef union { void *vp; lzo_bytep bp; lzo_uint u; lzo_uint32 u32; unsigned long l; } lzo_align_t;
-/* align a char pointer on a boundary that is a multiple of `size' */
-LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size);
-#define LZO_PTR_ALIGN_UP(_ptr,_size) \
- ((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size)))
+/* align a char pointer on a boundary that is a multiple of 'size' */
+LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size);
+#define LZO_PTR_ALIGN_UP(p,size) \
+ ((p) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(p),(lzo_uint)(size)))
/***********************************************************************
@@ -395,8 +424,8 @@ LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size);
# define __LZO_WIN 1
#endif
-#define __LZO_CMODEL
-#define __LZO_DMODEL
+#define __LZO_CMODEL /*empty*/
+#define __LZO_DMODEL /*empty*/
#define __LZO_ENTRY __LZO_CDECL
#define LZO_EXTERN_CDECL LZO_EXTERN
#define LZO_ALIGN LZO_PTR_ALIGN_UP
diff --git a/extern/lzo/minilzo/lzodefs.h b/extern/lzo/minilzo/lzodefs.h
index 180563723e5..0e40e332a8d 100644
--- a/extern/lzo/minilzo/lzodefs.h
+++ b/extern/lzo/minilzo/lzodefs.h
@@ -2,6 +2,9 @@
This file is part of the LZO real-time data compression library.
+ Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
@@ -121,7 +124,7 @@
#endif
#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL)
# define ptrdiff_t long
-# define _PTRDIFF_T_DEFINED
+# define _PTRDIFF_T_DEFINED 1
#endif
#if (UINT_MAX == LZO_0xffffL)
# undef __LZO_RENAME_A
@@ -265,9 +268,9 @@
# define LZO_EXTERN_C extern
#endif
#if !defined(__LZO_OS_OVERRIDE)
-#if defined(LZO_OS_FREESTANDING)
+#if (LZO_OS_FREESTANDING)
# define LZO_INFO_OS "freestanding"
-#elif defined(LZO_OS_EMBEDDED)
+#elif (LZO_OS_EMBEDDED)
# define LZO_INFO_OS "embedded"
#elif 1 && defined(__IAR_SYSTEMS_ICC__)
# define LZO_OS_EMBEDDED 1
@@ -476,12 +479,27 @@
# define LZO_CC_PELLESC 1
# define LZO_INFO_CC "Pelles C"
# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__)
-#elif defined(__llvm__) && defined(__GNUC__) && defined(__VERSION__)
-# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
-# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+#elif defined(__clang__) && defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+# if defined(__GNUC_PATCHLEVEL__)
+# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+# else
+# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+# endif
+# if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__)
+# define LZO_CC_CLANG_CLANG (__clang_major__ * 0x10000L + __clang_minor__ * 0x100 + __clang_patchlevel__)
+# else
+# define LZO_CC_CLANG_CLANG 0x010000L
+# endif
+# define LZO_CC_CLANG LZO_CC_CLANG_GNUC
+# define LZO_INFO_CC "clang"
+# define LZO_INFO_CCVER __VERSION__
+#elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+# if defined(__GNUC_PATCHLEVEL__)
+# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
# else
-# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
# endif
+# define LZO_CC_LLVM LZO_CC_LLVM_GNUC
# define LZO_INFO_CC "llvm-gcc"
# define LZO_INFO_CCVER __VERSION__
#elif defined(__GNUC__) && defined(__VERSION__)
@@ -502,6 +520,10 @@
# define LZO_CC_AZTECC 1
# define LZO_INFO_CC "Aztec C"
# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__)
+#elif defined(__CODEGEARC__)
+# define LZO_CC_CODEGEARC 1
+# define LZO_INFO_CC "CodeGear C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CODEGEARC__)
#elif defined(__BORLANDC__)
# define LZO_CC_BORLANDC 1
# define LZO_INFO_CC "Borland C"
@@ -632,7 +654,7 @@
#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER)
# error "LZO_CC_MSC: _MSC_FULL_VER is not defined"
#endif
-#if !defined(__LZO_ARCH_OVERRIDE) && !defined(LZO_ARCH_GENERIC) && defined(_CRAY)
+#if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY)
# if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY)
# if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E)
# define LZO_ARCH_CRAY_MPP 1
@@ -642,7 +664,7 @@
# endif
#endif
#if !defined(__LZO_ARCH_OVERRIDE)
-#if defined(LZO_ARCH_GENERIC)
+#if (LZO_ARCH_GENERIC)
# define LZO_INFO_ARCH "generic"
#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
# define LZO_ARCH_I086 1
@@ -677,6 +699,9 @@
#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__)
# define LZO_ARCH_AVR 1
# define LZO_INFO_ARCH "avr"
+#elif defined(__avr32__) || defined(__AVR32__)
+# define LZO_ARCH_AVR32 1
+# define LZO_INFO_ARCH "avr32"
#elif defined(__bfin__)
# define LZO_ARCH_BLACKFIN 1
# define LZO_INFO_ARCH "blackfin"
@@ -799,10 +824,10 @@
# define LZO_ARCH_I086PM 1
# define LZO_ARCH_IA16PM 1
#endif
-#if defined(LZO_ARCH_ARM_THUMB) && !defined(LZO_ARCH_ARM)
+#if (LZO_ARCH_ARM_THUMB) && !(LZO_ARCH_ARM)
# error "this should not happen"
#endif
-#if defined(LZO_ARCH_I086PM) && !defined(LZO_ARCH_I086)
+#if (LZO_ARCH_I086PM) && !(LZO_ARCH_I086)
# error "this should not happen"
#endif
#if (LZO_ARCH_I086)
@@ -875,7 +900,7 @@
#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295))
# undef LZO_HAVE_MM_HUGE_ARRAY
#endif
-#if (LZO_ARCH_I086PM) && !defined(LZO_HAVE_MM_HUGE_PTR)
+#if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR)
# if (LZO_OS_DOS16)
# error "this should not happen"
# elif (LZO_CC_ZORTECHC)
@@ -1091,7 +1116,7 @@ extern "C" {
#if (LZO_ARCH_I086 && LZO_CC_DMC)
#elif (LZO_CC_CILLY) && defined(__GNUC__)
# define LZO_SIZEOF_LONG_LONG 8
-#elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define LZO_SIZEOF_LONG_LONG 8
#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400))
# define LZO_SIZEOF_LONG_LONG 8
@@ -1125,12 +1150,12 @@ extern "C" {
#endif
#endif
#endif
-#if defined(__cplusplus) && defined(LZO_CC_GNUC)
+#if defined(__cplusplus) && (LZO_CC_GNUC)
# if (LZO_CC_GNUC < 0x020800ul)
# undef LZO_SIZEOF_LONG_LONG
# endif
#endif
-#if defined(LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG)
+#if (LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG)
# undef LZO_SIZEOF_LONG_LONG
#endif
#if !defined(LZO_SIZEOF_VOID_P)
@@ -1229,15 +1254,17 @@ extern "C" {
# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T
#endif
#endif
-#if defined(LZO_ABI_NEUTRAL_ENDIAN)
+#if (LZO_ABI_NEUTRAL_ENDIAN)
# undef LZO_ABI_BIG_ENDIAN
# undef LZO_ABI_LITTLE_ENDIAN
-#elif !defined(LZO_ABI_BIG_ENDIAN) && !defined(LZO_ABI_LITTLE_ENDIAN)
+#elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN)
#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP)
# define LZO_ABI_BIG_ENDIAN 1
+#elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64)
+# define LZO_ABI_LITTLE_ENDIAN 1
#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430)
# define LZO_ABI_LITTLE_ENDIAN 1
-#elif (LZO_ARCH_M68K || LZO_ARCH_S390)
+#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390)
# define LZO_ABI_BIG_ENDIAN 1
#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__)
# if (__LITTLE_ENDIAN__ == 1)
@@ -1259,14 +1286,14 @@ extern "C" {
# define LZO_ABI_LITTLE_ENDIAN 1
#endif
#endif
-#if defined(LZO_ABI_BIG_ENDIAN) && defined(LZO_ABI_LITTLE_ENDIAN)
+#if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN)
# error "this should not happen"
#endif
-#if defined(LZO_ABI_BIG_ENDIAN)
+#if (LZO_ABI_BIG_ENDIAN)
# define LZO_INFO_ABI_ENDIAN "be"
-#elif defined(LZO_ABI_LITTLE_ENDIAN)
+#elif (LZO_ABI_LITTLE_ENDIAN)
# define LZO_INFO_ABI_ENDIAN "le"
-#elif defined(LZO_ABI_NEUTRAL_ENDIAN)
+#elif (LZO_ABI_NEUTRAL_ENDIAN)
# define LZO_INFO_ABI_ENDIAN "neutral"
#endif
#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)
@@ -1292,15 +1319,15 @@ extern "C" {
# define LZO_INFO_ABI_PM "ip32l64"
#endif
#if !defined(__LZO_LIBC_OVERRIDE)
-#if defined(LZO_LIBC_NAKED)
+#if (LZO_LIBC_NAKED)
# define LZO_INFO_LIBC "naked"
-#elif defined(LZO_LIBC_FREESTANDING)
+#elif (LZO_LIBC_FREESTANDING)
# define LZO_INFO_LIBC "freestanding"
-#elif defined(LZO_LIBC_MOSTLY_FREESTANDING)
+#elif (LZO_LIBC_MOSTLY_FREESTANDING)
# define LZO_INFO_LIBC "mfreestanding"
-#elif defined(LZO_LIBC_ISOC90)
+#elif (LZO_LIBC_ISOC90)
# define LZO_INFO_LIBC "isoc90"
-#elif defined(LZO_LIBC_ISOC99)
+#elif (LZO_LIBC_ISOC99)
# define LZO_INFO_LIBC "isoc99"
#elif defined(__dietlibc__)
# define LZO_LIBC_DIETLIBC 1
@@ -1332,22 +1359,24 @@ extern "C" {
#if !defined(__lzo_gnuc_extension__)
#if (LZO_CC_GNUC >= 0x020800ul)
# define __lzo_gnuc_extension__ __extension__
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_gnuc_extension__ __extension__
#else
-# define __lzo_gnuc_extension__
+# define __lzo_gnuc_extension__ /*empty*/
#endif
#endif
#if !defined(__lzo_ua_volatile)
# define __lzo_ua_volatile volatile
#endif
#if !defined(__lzo_alignof)
-#if (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+#if (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
# define __lzo_alignof(e) __alignof__(e)
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700))
# define __lzo_alignof(e) __alignof__(e)
#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
# define __lzo_alignof(e) __alignof(e)
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+# define __lzo_alignof(e) __alignof__(e)
#endif
#endif
#if defined(__lzo_alignof)
@@ -1358,7 +1387,7 @@ extern "C" {
# define __lzo_constructor __attribute__((__constructor__,__used__))
#elif (LZO_CC_GNUC >= 0x020700ul)
# define __lzo_constructor __attribute__((__constructor__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_constructor __attribute__((__constructor__))
#endif
#endif
@@ -1370,14 +1399,14 @@ extern "C" {
# define __lzo_destructor __attribute__((__destructor__,__used__))
#elif (LZO_CC_GNUC >= 0x020700ul)
# define __lzo_destructor __attribute__((__destructor__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_destructor __attribute__((__destructor__))
#endif
#endif
#if defined(__lzo_destructor)
# define __lzo_HAVE_destructor 1
#endif
-#if defined(__lzo_HAVE_destructor) && !defined(__lzo_HAVE_constructor)
+#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor)
# error "this should not happen"
#endif
#if !defined(__lzo_inline)
@@ -1386,7 +1415,7 @@ extern "C" {
# define __lzo_inline inline
#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550))
# define __lzo_inline __inline
-#elif (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
# define __lzo_inline __inline__
#elif (LZO_CC_DMC)
# define __lzo_inline __inline
@@ -1396,6 +1425,8 @@ extern "C" {
# define __lzo_inline __inline
#elif (LZO_CC_MSC && (_MSC_VER >= 900))
# define __lzo_inline __inline
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+# define __lzo_inline __inline__
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
# define __lzo_inline inline
#endif
@@ -1403,7 +1434,7 @@ extern "C" {
#if defined(__lzo_inline)
# define __lzo_HAVE_inline 1
#else
-# define __lzo_inline
+# define __lzo_inline /*empty*/
#endif
#if !defined(__lzo_forceinline)
#if (LZO_CC_GNUC >= 0x030200ul)
@@ -1412,16 +1443,18 @@ extern "C" {
# define __lzo_forceinline __forceinline
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
# define __lzo_forceinline __forceinline
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
#endif
#endif
#if defined(__lzo_forceinline)
# define __lzo_HAVE_forceinline 1
#else
-# define __lzo_forceinline
+# define __lzo_forceinline /*empty*/
#endif
#if !defined(__lzo_noinline)
#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul)
@@ -1432,7 +1465,7 @@ extern "C" {
# define __lzo_noinline __declspec(noinline)
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
# define __lzo_noinline __attribute__((__noinline__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_noinline __attribute__((__noinline__))
#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
# define __lzo_noinline __declspec(noinline)
@@ -1441,14 +1474,16 @@ extern "C" {
# else
# define __lzo_noinline __declspec(noinline)
# endif
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+# define __lzo_noinline __attribute__((__noinline__))
#endif
#endif
#if defined(__lzo_noinline)
# define __lzo_HAVE_noinline 1
#else
-# define __lzo_noinline
+# define __lzo_noinline /*empty*/
#endif
-#if (defined(__lzo_HAVE_forceinline) || defined(__lzo_HAVE_noinline)) && !defined(__lzo_HAVE_inline)
+#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline)
# error "this should not happen"
#endif
#if !defined(__lzo_noreturn)
@@ -1458,7 +1493,7 @@ extern "C" {
# define __lzo_noreturn __declspec(noreturn)
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
# define __lzo_noreturn __attribute__((__noreturn__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_noreturn __attribute__((__noreturn__))
#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
# define __lzo_noreturn __declspec(noreturn)
@@ -1467,16 +1502,16 @@ extern "C" {
#if defined(__lzo_noreturn)
# define __lzo_HAVE_noreturn 1
#else
-# define __lzo_noreturn
+# define __lzo_noreturn /*empty*/
#endif
#if !defined(__lzo_nothrow)
#if (LZO_CC_GNUC >= 0x030300ul)
# define __lzo_nothrow __attribute__((__nothrow__))
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus)
# define __lzo_nothrow __declspec(nothrow)
-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 900) && LZO_CC_SYNTAX_GNUC)
# define __lzo_nothrow __attribute__((__nothrow__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_nothrow __attribute__((__nothrow__))
#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus)
# define __lzo_nothrow __declspec(nothrow)
@@ -1485,14 +1520,14 @@ extern "C" {
#if defined(__lzo_nothrow)
# define __lzo_HAVE_nothrow 1
#else
-# define __lzo_nothrow
+# define __lzo_nothrow /*empty*/
#endif
#if !defined(__lzo_restrict)
#if (LZO_CC_GNUC >= 0x030400ul)
# define __lzo_restrict __restrict__
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
# define __lzo_restrict __restrict__
-#elif (LZO_CC_LLVM)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM)
# define __lzo_restrict __restrict__
#elif (LZO_CC_MSC && (_MSC_VER >= 1400))
# define __lzo_restrict __restrict
@@ -1501,7 +1536,7 @@ extern "C" {
#if defined(__lzo_restrict)
# define __lzo_HAVE_restrict 1
#else
-# define __lzo_restrict
+# define __lzo_restrict /*empty*/
#endif
#if !defined(__lzo_likely) && !defined(__lzo_unlikely)
#if (LZO_CC_GNUC >= 0x030200ul)
@@ -1510,7 +1545,7 @@ extern "C" {
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800))
# define __lzo_likely(e) (__builtin_expect(!!(e),1))
# define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_likely(e) (__builtin_expect(!!(e),1))
# define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
#endif
@@ -1530,7 +1565,7 @@ extern "C" {
# define LZO_UNUSED(var) ((void) &var)
# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC)
# define LZO_UNUSED(var) if (&var) ; else
-# elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define LZO_UNUSED(var) ((void) var)
# elif (LZO_CC_MSC && (_MSC_VER < 900))
# define LZO_UNUSED(var) if (&var) ; else
@@ -1549,7 +1584,7 @@ extern "C" {
# define LZO_UNUSED_FUNC(func) ((void) func)
# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC)
# define LZO_UNUSED_FUNC(func) if (func) ; else
-# elif (LZO_CC_LLVM)
+# elif (LZO_CC_CLANG || LZO_CC_LLVM)
# define LZO_UNUSED_FUNC(func) ((void) &func)
# elif (LZO_CC_MSC && (_MSC_VER < 900))
# define LZO_UNUSED_FUNC(func) if (func) ; else
@@ -1564,7 +1599,7 @@ extern "C" {
#if !defined(LZO_UNUSED_LABEL)
# if (LZO_CC_WATCOMC) && defined(__cplusplus)
# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l
-# elif (LZO_CC_INTELC || LZO_CC_WATCOMC)
+# elif (LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC)
# define LZO_UNUSED_LABEL(l) if (0) goto l
# else
# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l
@@ -1579,6 +1614,15 @@ extern "C" {
# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init
# endif
#endif
+#if !defined(LZO_UNCONST_CAST)
+# if 0 && defined(__cplusplus)
+# define LZO_UNCONST_CAST(t,e) (const_cast<t> (e))
+# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((lzo_uintptr_t) ((const void *) (e))))))
+# else
+# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((const void *) (e)))))
+# endif
+#endif
#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER)
# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC)
# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)];
@@ -1607,7 +1651,7 @@ extern "C" {
# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC)
# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
# define __lzo_cdecl __cdecl
-# define __lzo_cdecl_atexit
+# define __lzo_cdecl_atexit /*empty*/
# define __lzo_cdecl_main __cdecl
# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
# define __lzo_cdecl_qsort __pascal
@@ -1648,24 +1692,24 @@ extern "C" {
# define __lzo_cdecl cdecl
#endif
#if !defined(__lzo_cdecl)
-# define __lzo_cdecl
+# define __lzo_cdecl /*empty*/
#endif
#if !defined(__lzo_cdecl_atexit)
-# define __lzo_cdecl_atexit
+# define __lzo_cdecl_atexit /*empty*/
#endif
#if !defined(__lzo_cdecl_main)
-# define __lzo_cdecl_main
+# define __lzo_cdecl_main /*empty*/
#endif
#if !defined(__lzo_cdecl_qsort)
-# define __lzo_cdecl_qsort
+# define __lzo_cdecl_qsort /*empty*/
#endif
#if !defined(__lzo_cdecl_sighandler)
-# define __lzo_cdecl_sighandler
+# define __lzo_cdecl_sighandler /*empty*/
#endif
#if !defined(__lzo_cdecl_va)
# define __lzo_cdecl_va __lzo_cdecl
#endif
-#if !defined(LZO_CFG_NO_WINDOWS_H)
+#if !(LZO_CFG_NO_WINDOWS_H)
#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64)
# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000))
# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__)
@@ -1711,7 +1755,7 @@ extern "C" {
#elif (LZO_ARCH_POWERPC)
# define LZO_OPT_PREFER_PREINC 1
# define LZO_OPT_PREFER_PREDEC 1
-# if defined(LZO_ABI_BIG_ENDIAN)
+# if (LZO_ABI_BIG_ENDIAN)
# define LZO_OPT_UNALIGNED16 1
# define LZO_OPT_UNALIGNED32 1
# endif
@@ -1725,28 +1769,29 @@ extern "C" {
# define LZO_OPT_PREFER_POSTINC 1
# define LZO_OPT_PREFER_PREDEC 1
#endif
-#if !defined(LZO_CFG_NO_INLINE_ASM)
-#if defined(LZO_CC_LLVM)
+#ifndef LZO_CFG_NO_INLINE_ASM
+#if (LZO_CC_LLVM)
# define LZO_CFG_NO_INLINE_ASM 1
#endif
#endif
-#if !defined(LZO_CFG_NO_UNALIGNED)
-#if defined(LZO_ABI_NEUTRAL_ENDIAN) || defined(LZO_ARCH_GENERIC)
+#ifndef LZO_CFG_NO_UNALIGNED
+#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC)
# define LZO_CFG_NO_UNALIGNED 1
#endif
#endif
-#if defined(LZO_CFG_NO_UNALIGNED)
+#if (LZO_CFG_NO_UNALIGNED)
# undef LZO_OPT_UNALIGNED16
# undef LZO_OPT_UNALIGNED32
# undef LZO_OPT_UNALIGNED64
#endif
-#if defined(LZO_CFG_NO_INLINE_ASM)
+#if (LZO_CFG_NO_INLINE_ASM)
#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
# define LZO_ASM_SYNTAX_MSC 1
#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
-#elif (LZO_ARCH_I386 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul))
+#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
# define LZO_ASM_SYNTAX_GNUC 1
-#elif (LZO_ARCH_AMD64 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
# define LZO_ASM_SYNTAX_GNUC 1
#endif
#if (LZO_ASM_SYNTAX_GNUC)
diff --git a/extern/lzo/minilzo/minilzo.c b/extern/lzo/minilzo/minilzo.c
index 6a62b31b94a..34ce0f090bd 100644
--- a/extern/lzo/minilzo/minilzo.c
+++ b/extern/lzo/minilzo/minilzo.c
@@ -2,6 +2,9 @@
This file is part of the LZO real-time data compression library.
+ Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
@@ -43,8 +46,7 @@
* http://www.oberhumer.com/opensource/lzo/
*/
-#define __LZO_IN_MINILZO
-#define LZO_BUILD
+#define __LZO_IN_MINILZO 1
#if defined(LZO_CFG_FREESTANDING)
# undef MINILZO_HAVE_CONFIG_H
@@ -142,7 +144,7 @@
#endif
#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL)
# define ptrdiff_t long
-# define _PTRDIFF_T_DEFINED
+# define _PTRDIFF_T_DEFINED 1
#endif
#if (UINT_MAX == LZO_0xffffL)
# undef __LZO_RENAME_A
@@ -286,9 +288,9 @@
# define LZO_EXTERN_C extern
#endif
#if !defined(__LZO_OS_OVERRIDE)
-#if defined(LZO_OS_FREESTANDING)
+#if (LZO_OS_FREESTANDING)
# define LZO_INFO_OS "freestanding"
-#elif defined(LZO_OS_EMBEDDED)
+#elif (LZO_OS_EMBEDDED)
# define LZO_INFO_OS "embedded"
#elif 1 && defined(__IAR_SYSTEMS_ICC__)
# define LZO_OS_EMBEDDED 1
@@ -497,12 +499,27 @@
# define LZO_CC_PELLESC 1
# define LZO_INFO_CC "Pelles C"
# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__)
-#elif defined(__llvm__) && defined(__GNUC__) && defined(__VERSION__)
-# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
-# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+#elif defined(__clang__) && defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+# if defined(__GNUC_PATCHLEVEL__)
+# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+# else
+# define LZO_CC_CLANG_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+# endif
+# if defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__)
+# define LZO_CC_CLANG_CLANG (__clang_major__ * 0x10000L + __clang_minor__ * 0x100 + __clang_patchlevel__)
# else
-# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+# define LZO_CC_CLANG_CLANG 0x010000L
# endif
+# define LZO_CC_CLANG LZO_CC_CLANG_GNUC
+# define LZO_INFO_CC "clang"
+# define LZO_INFO_CCVER __VERSION__
+#elif defined(__llvm__) && defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__VERSION__)
+# if defined(__GNUC_PATCHLEVEL__)
+# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+# else
+# define LZO_CC_LLVM_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+# endif
+# define LZO_CC_LLVM LZO_CC_LLVM_GNUC
# define LZO_INFO_CC "llvm-gcc"
# define LZO_INFO_CCVER __VERSION__
#elif defined(__GNUC__) && defined(__VERSION__)
@@ -523,6 +540,10 @@
# define LZO_CC_AZTECC 1
# define LZO_INFO_CC "Aztec C"
# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__)
+#elif defined(__CODEGEARC__)
+# define LZO_CC_CODEGEARC 1
+# define LZO_INFO_CC "CodeGear C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CODEGEARC__)
#elif defined(__BORLANDC__)
# define LZO_CC_BORLANDC 1
# define LZO_INFO_CC "Borland C"
@@ -653,7 +674,7 @@
#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER)
# error "LZO_CC_MSC: _MSC_FULL_VER is not defined"
#endif
-#if !defined(__LZO_ARCH_OVERRIDE) && !defined(LZO_ARCH_GENERIC) && defined(_CRAY)
+#if !defined(__LZO_ARCH_OVERRIDE) && !(LZO_ARCH_GENERIC) && defined(_CRAY)
# if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY)
# if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E)
# define LZO_ARCH_CRAY_MPP 1
@@ -663,7 +684,7 @@
# endif
#endif
#if !defined(__LZO_ARCH_OVERRIDE)
-#if defined(LZO_ARCH_GENERIC)
+#if (LZO_ARCH_GENERIC)
# define LZO_INFO_ARCH "generic"
#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
# define LZO_ARCH_I086 1
@@ -698,6 +719,9 @@
#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__)
# define LZO_ARCH_AVR 1
# define LZO_INFO_ARCH "avr"
+#elif defined(__avr32__) || defined(__AVR32__)
+# define LZO_ARCH_AVR32 1
+# define LZO_INFO_ARCH "avr32"
#elif defined(__bfin__)
# define LZO_ARCH_BLACKFIN 1
# define LZO_INFO_ARCH "blackfin"
@@ -820,10 +844,10 @@
# define LZO_ARCH_I086PM 1
# define LZO_ARCH_IA16PM 1
#endif
-#if defined(LZO_ARCH_ARM_THUMB) && !defined(LZO_ARCH_ARM)
+#if (LZO_ARCH_ARM_THUMB) && !(LZO_ARCH_ARM)
# error "this should not happen"
#endif
-#if defined(LZO_ARCH_I086PM) && !defined(LZO_ARCH_I086)
+#if (LZO_ARCH_I086PM) && !(LZO_ARCH_I086)
# error "this should not happen"
#endif
#if (LZO_ARCH_I086)
@@ -896,7 +920,7 @@
#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295))
# undef LZO_HAVE_MM_HUGE_ARRAY
#endif
-#if (LZO_ARCH_I086PM) && !defined(LZO_HAVE_MM_HUGE_PTR)
+#if (LZO_ARCH_I086PM) && !(LZO_HAVE_MM_HUGE_PTR)
# if (LZO_OS_DOS16)
# error "this should not happen"
# elif (LZO_CC_ZORTECHC)
@@ -1112,7 +1136,7 @@ extern "C" {
#if (LZO_ARCH_I086 && LZO_CC_DMC)
#elif (LZO_CC_CILLY) && defined(__GNUC__)
# define LZO_SIZEOF_LONG_LONG 8
-#elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define LZO_SIZEOF_LONG_LONG 8
#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400))
# define LZO_SIZEOF_LONG_LONG 8
@@ -1146,12 +1170,12 @@ extern "C" {
#endif
#endif
#endif
-#if defined(__cplusplus) && defined(LZO_CC_GNUC)
+#if defined(__cplusplus) && (LZO_CC_GNUC)
# if (LZO_CC_GNUC < 0x020800ul)
# undef LZO_SIZEOF_LONG_LONG
# endif
#endif
-#if defined(LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG)
+#if (LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG)
# undef LZO_SIZEOF_LONG_LONG
#endif
#if !defined(LZO_SIZEOF_VOID_P)
@@ -1250,15 +1274,17 @@ extern "C" {
# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T
#endif
#endif
-#if defined(LZO_ABI_NEUTRAL_ENDIAN)
+#if (LZO_ABI_NEUTRAL_ENDIAN)
# undef LZO_ABI_BIG_ENDIAN
# undef LZO_ABI_LITTLE_ENDIAN
-#elif !defined(LZO_ABI_BIG_ENDIAN) && !defined(LZO_ABI_LITTLE_ENDIAN)
+#elif !(LZO_ABI_BIG_ENDIAN) && !(LZO_ABI_LITTLE_ENDIAN)
#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP)
# define LZO_ABI_BIG_ENDIAN 1
+#elif (LZO_ARCH_IA64) && (LZO_OS_POSIX_LINUX || LZO_OS_WIN64)
+# define LZO_ABI_LITTLE_ENDIAN 1
#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430)
# define LZO_ABI_LITTLE_ENDIAN 1
-#elif (LZO_ARCH_M68K || LZO_ARCH_S390)
+#elif (LZO_ARCH_AVR32 || LZO_ARCH_M68K || LZO_ARCH_S390)
# define LZO_ABI_BIG_ENDIAN 1
#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__)
# if (__LITTLE_ENDIAN__ == 1)
@@ -1280,14 +1306,14 @@ extern "C" {
# define LZO_ABI_LITTLE_ENDIAN 1
#endif
#endif
-#if defined(LZO_ABI_BIG_ENDIAN) && defined(LZO_ABI_LITTLE_ENDIAN)
+#if (LZO_ABI_BIG_ENDIAN) && (LZO_ABI_LITTLE_ENDIAN)
# error "this should not happen"
#endif
-#if defined(LZO_ABI_BIG_ENDIAN)
+#if (LZO_ABI_BIG_ENDIAN)
# define LZO_INFO_ABI_ENDIAN "be"
-#elif defined(LZO_ABI_LITTLE_ENDIAN)
+#elif (LZO_ABI_LITTLE_ENDIAN)
# define LZO_INFO_ABI_ENDIAN "le"
-#elif defined(LZO_ABI_NEUTRAL_ENDIAN)
+#elif (LZO_ABI_NEUTRAL_ENDIAN)
# define LZO_INFO_ABI_ENDIAN "neutral"
#endif
#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)
@@ -1313,15 +1339,15 @@ extern "C" {
# define LZO_INFO_ABI_PM "ip32l64"
#endif
#if !defined(__LZO_LIBC_OVERRIDE)
-#if defined(LZO_LIBC_NAKED)
+#if (LZO_LIBC_NAKED)
# define LZO_INFO_LIBC "naked"
-#elif defined(LZO_LIBC_FREESTANDING)
+#elif (LZO_LIBC_FREESTANDING)
# define LZO_INFO_LIBC "freestanding"
-#elif defined(LZO_LIBC_MOSTLY_FREESTANDING)
+#elif (LZO_LIBC_MOSTLY_FREESTANDING)
# define LZO_INFO_LIBC "mfreestanding"
-#elif defined(LZO_LIBC_ISOC90)
+#elif (LZO_LIBC_ISOC90)
# define LZO_INFO_LIBC "isoc90"
-#elif defined(LZO_LIBC_ISOC99)
+#elif (LZO_LIBC_ISOC99)
# define LZO_INFO_LIBC "isoc99"
#elif defined(__dietlibc__)
# define LZO_LIBC_DIETLIBC 1
@@ -1353,22 +1379,24 @@ extern "C" {
#if !defined(__lzo_gnuc_extension__)
#if (LZO_CC_GNUC >= 0x020800ul)
# define __lzo_gnuc_extension__ __extension__
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_gnuc_extension__ __extension__
#else
-# define __lzo_gnuc_extension__
+# define __lzo_gnuc_extension__ /*empty*/
#endif
#endif
#if !defined(__lzo_ua_volatile)
# define __lzo_ua_volatile volatile
#endif
#if !defined(__lzo_alignof)
-#if (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+#if (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
# define __lzo_alignof(e) __alignof__(e)
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700))
# define __lzo_alignof(e) __alignof__(e)
#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
# define __lzo_alignof(e) __alignof(e)
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+# define __lzo_alignof(e) __alignof__(e)
#endif
#endif
#if defined(__lzo_alignof)
@@ -1379,7 +1407,7 @@ extern "C" {
# define __lzo_constructor __attribute__((__constructor__,__used__))
#elif (LZO_CC_GNUC >= 0x020700ul)
# define __lzo_constructor __attribute__((__constructor__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_constructor __attribute__((__constructor__))
#endif
#endif
@@ -1391,14 +1419,14 @@ extern "C" {
# define __lzo_destructor __attribute__((__destructor__,__used__))
#elif (LZO_CC_GNUC >= 0x020700ul)
# define __lzo_destructor __attribute__((__destructor__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_destructor __attribute__((__destructor__))
#endif
#endif
#if defined(__lzo_destructor)
# define __lzo_HAVE_destructor 1
#endif
-#if defined(__lzo_HAVE_destructor) && !defined(__lzo_HAVE_constructor)
+#if (__lzo_HAVE_destructor) && !(__lzo_HAVE_constructor)
# error "this should not happen"
#endif
#if !defined(__lzo_inline)
@@ -1407,7 +1435,7 @@ extern "C" {
# define __lzo_inline inline
#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550))
# define __lzo_inline __inline
-#elif (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+#elif (LZO_CC_CILLY || LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
# define __lzo_inline __inline__
#elif (LZO_CC_DMC)
# define __lzo_inline __inline
@@ -1417,6 +1445,8 @@ extern "C" {
# define __lzo_inline __inline
#elif (LZO_CC_MSC && (_MSC_VER >= 900))
# define __lzo_inline __inline
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+# define __lzo_inline __inline__
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
# define __lzo_inline inline
#endif
@@ -1424,7 +1454,7 @@ extern "C" {
#if defined(__lzo_inline)
# define __lzo_HAVE_inline 1
#else
-# define __lzo_inline
+# define __lzo_inline /*empty*/
#endif
#if !defined(__lzo_forceinline)
#if (LZO_CC_GNUC >= 0x030200ul)
@@ -1433,16 +1463,18 @@ extern "C" {
# define __lzo_forceinline __forceinline
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
# define __lzo_forceinline __forceinline
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
#endif
#endif
#if defined(__lzo_forceinline)
# define __lzo_HAVE_forceinline 1
#else
-# define __lzo_forceinline
+# define __lzo_forceinline /*empty*/
#endif
#if !defined(__lzo_noinline)
#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul)
@@ -1453,7 +1485,7 @@ extern "C" {
# define __lzo_noinline __declspec(noinline)
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
# define __lzo_noinline __attribute__((__noinline__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_noinline __attribute__((__noinline__))
#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
# define __lzo_noinline __declspec(noinline)
@@ -1462,14 +1494,16 @@ extern "C" {
# else
# define __lzo_noinline __declspec(noinline)
# endif
+#elif (LZO_CC_SUNPROC && (LZO_CC_SUNPROC >= 0x5100))
+# define __lzo_noinline __attribute__((__noinline__))
#endif
#endif
#if defined(__lzo_noinline)
# define __lzo_HAVE_noinline 1
#else
-# define __lzo_noinline
+# define __lzo_noinline /*empty*/
#endif
-#if (defined(__lzo_HAVE_forceinline) || defined(__lzo_HAVE_noinline)) && !defined(__lzo_HAVE_inline)
+#if (__lzo_HAVE_forceinline || __lzo_HAVE_noinline) && !(__lzo_HAVE_inline)
# error "this should not happen"
#endif
#if !defined(__lzo_noreturn)
@@ -1479,7 +1513,7 @@ extern "C" {
# define __lzo_noreturn __declspec(noreturn)
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
# define __lzo_noreturn __attribute__((__noreturn__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_noreturn __attribute__((__noreturn__))
#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
# define __lzo_noreturn __declspec(noreturn)
@@ -1488,16 +1522,16 @@ extern "C" {
#if defined(__lzo_noreturn)
# define __lzo_HAVE_noreturn 1
#else
-# define __lzo_noreturn
+# define __lzo_noreturn /*empty*/
#endif
#if !defined(__lzo_nothrow)
#if (LZO_CC_GNUC >= 0x030300ul)
# define __lzo_nothrow __attribute__((__nothrow__))
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus)
# define __lzo_nothrow __declspec(nothrow)
-#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 900) && LZO_CC_SYNTAX_GNUC)
# define __lzo_nothrow __attribute__((__nothrow__))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_nothrow __attribute__((__nothrow__))
#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus)
# define __lzo_nothrow __declspec(nothrow)
@@ -1506,14 +1540,14 @@ extern "C" {
#if defined(__lzo_nothrow)
# define __lzo_HAVE_nothrow 1
#else
-# define __lzo_nothrow
+# define __lzo_nothrow /*empty*/
#endif
#if !defined(__lzo_restrict)
#if (LZO_CC_GNUC >= 0x030400ul)
# define __lzo_restrict __restrict__
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
# define __lzo_restrict __restrict__
-#elif (LZO_CC_LLVM)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM)
# define __lzo_restrict __restrict__
#elif (LZO_CC_MSC && (_MSC_VER >= 1400))
# define __lzo_restrict __restrict
@@ -1522,7 +1556,7 @@ extern "C" {
#if defined(__lzo_restrict)
# define __lzo_HAVE_restrict 1
#else
-# define __lzo_restrict
+# define __lzo_restrict /*empty*/
#endif
#if !defined(__lzo_likely) && !defined(__lzo_unlikely)
#if (LZO_CC_GNUC >= 0x030200ul)
@@ -1531,7 +1565,7 @@ extern "C" {
#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800))
# define __lzo_likely(e) (__builtin_expect(!!(e),1))
# define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
-#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+#elif (LZO_CC_CLANG || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define __lzo_likely(e) (__builtin_expect(!!(e),1))
# define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
#endif
@@ -1551,7 +1585,7 @@ extern "C" {
# define LZO_UNUSED(var) ((void) &var)
# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC)
# define LZO_UNUSED(var) if (&var) ; else
-# elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
# define LZO_UNUSED(var) ((void) var)
# elif (LZO_CC_MSC && (_MSC_VER < 900))
# define LZO_UNUSED(var) if (&var) ; else
@@ -1570,7 +1604,7 @@ extern "C" {
# define LZO_UNUSED_FUNC(func) ((void) func)
# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC)
# define LZO_UNUSED_FUNC(func) if (func) ; else
-# elif (LZO_CC_LLVM)
+# elif (LZO_CC_CLANG || LZO_CC_LLVM)
# define LZO_UNUSED_FUNC(func) ((void) &func)
# elif (LZO_CC_MSC && (_MSC_VER < 900))
# define LZO_UNUSED_FUNC(func) if (func) ; else
@@ -1585,7 +1619,7 @@ extern "C" {
#if !defined(LZO_UNUSED_LABEL)
# if (LZO_CC_WATCOMC) && defined(__cplusplus)
# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l
-# elif (LZO_CC_INTELC || LZO_CC_WATCOMC)
+# elif (LZO_CC_CLANG || LZO_CC_INTELC || LZO_CC_WATCOMC)
# define LZO_UNUSED_LABEL(l) if (0) goto l
# else
# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l
@@ -1600,6 +1634,15 @@ extern "C" {
# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init
# endif
#endif
+#if !defined(LZO_UNCONST_CAST)
+# if 0 && defined(__cplusplus)
+# define LZO_UNCONST_CAST(t,e) (const_cast<t> (e))
+# elif (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((lzo_uintptr_t) ((const void *) (e))))))
+# else
+# define LZO_UNCONST_CAST(t,e) ((t) ((void *) ((char *) ((const void *) (e)))))
+# endif
+#endif
#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER)
# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC)
# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)];
@@ -1628,7 +1671,7 @@ extern "C" {
# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC)
# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
# define __lzo_cdecl __cdecl
-# define __lzo_cdecl_atexit
+# define __lzo_cdecl_atexit /*empty*/
# define __lzo_cdecl_main __cdecl
# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
# define __lzo_cdecl_qsort __pascal
@@ -1669,24 +1712,24 @@ extern "C" {
# define __lzo_cdecl cdecl
#endif
#if !defined(__lzo_cdecl)
-# define __lzo_cdecl
+# define __lzo_cdecl /*empty*/
#endif
#if !defined(__lzo_cdecl_atexit)
-# define __lzo_cdecl_atexit
+# define __lzo_cdecl_atexit /*empty*/
#endif
#if !defined(__lzo_cdecl_main)
-# define __lzo_cdecl_main
+# define __lzo_cdecl_main /*empty*/
#endif
#if !defined(__lzo_cdecl_qsort)
-# define __lzo_cdecl_qsort
+# define __lzo_cdecl_qsort /*empty*/
#endif
#if !defined(__lzo_cdecl_sighandler)
-# define __lzo_cdecl_sighandler
+# define __lzo_cdecl_sighandler /*empty*/
#endif
#if !defined(__lzo_cdecl_va)
# define __lzo_cdecl_va __lzo_cdecl
#endif
-#if !defined(LZO_CFG_NO_WINDOWS_H)
+#if !(LZO_CFG_NO_WINDOWS_H)
#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64)
# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000))
# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__)
@@ -1732,7 +1775,7 @@ extern "C" {
#elif (LZO_ARCH_POWERPC)
# define LZO_OPT_PREFER_PREINC 1
# define LZO_OPT_PREFER_PREDEC 1
-# if defined(LZO_ABI_BIG_ENDIAN)
+# if (LZO_ABI_BIG_ENDIAN)
# define LZO_OPT_UNALIGNED16 1
# define LZO_OPT_UNALIGNED32 1
# endif
@@ -1746,28 +1789,29 @@ extern "C" {
# define LZO_OPT_PREFER_POSTINC 1
# define LZO_OPT_PREFER_PREDEC 1
#endif
-#if !defined(LZO_CFG_NO_INLINE_ASM)
-#if defined(LZO_CC_LLVM)
+#ifndef LZO_CFG_NO_INLINE_ASM
+#if (LZO_CC_LLVM)
# define LZO_CFG_NO_INLINE_ASM 1
#endif
#endif
-#if !defined(LZO_CFG_NO_UNALIGNED)
-#if defined(LZO_ABI_NEUTRAL_ENDIAN) || defined(LZO_ARCH_GENERIC)
+#ifndef LZO_CFG_NO_UNALIGNED
+#if (LZO_ABI_NEUTRAL_ENDIAN) || (LZO_ARCH_GENERIC)
# define LZO_CFG_NO_UNALIGNED 1
#endif
#endif
-#if defined(LZO_CFG_NO_UNALIGNED)
+#if (LZO_CFG_NO_UNALIGNED)
# undef LZO_OPT_UNALIGNED16
# undef LZO_OPT_UNALIGNED32
# undef LZO_OPT_UNALIGNED64
#endif
-#if defined(LZO_CFG_NO_INLINE_ASM)
+#if (LZO_CFG_NO_INLINE_ASM)
#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
# define LZO_ASM_SYNTAX_MSC 1
#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
-#elif (LZO_ARCH_I386 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+#elif (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC == 0x011f00ul))
+#elif (LZO_ARCH_I386 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
# define LZO_ASM_SYNTAX_GNUC 1
-#elif (LZO_ARCH_AMD64 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+#elif (LZO_ARCH_AMD64 && (LZO_CC_CLANG || LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
# define LZO_ASM_SYNTAX_GNUC 1
#endif
#if (LZO_ASM_SYNTAX_GNUC)
@@ -1830,34 +1874,34 @@ extern "C" {
#undef LZO_HAVE_CONFIG_H
#include "minilzo.h"
-#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2030)
+#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2060)
# error "version mismatch in miniLZO source files"
#endif
#ifdef MINILZO_HAVE_CONFIG_H
-# define LZO_HAVE_CONFIG_H
+# define LZO_HAVE_CONFIG_H 1
#endif
#ifndef __LZO_CONF_H
-#define __LZO_CONF_H
+#define __LZO_CONF_H 1
#if !defined(__LZO_IN_MINILZO)
-#if defined(LZO_CFG_FREESTANDING)
+#if (LZO_CFG_FREESTANDING)
# define LZO_LIBC_FREESTANDING 1
# define LZO_OS_FREESTANDING 1
# define ACC_LIBC_FREESTANDING 1
# define ACC_OS_FREESTANDING 1
#endif
-#if defined(LZO_CFG_NO_UNALIGNED)
+#if (LZO_CFG_NO_UNALIGNED)
# define ACC_CFG_NO_UNALIGNED 1
#endif
-#if defined(LZO_ARCH_GENERIC)
+#if (LZO_ARCH_GENERIC)
# define ACC_ARCH_GENERIC 1
#endif
-#if defined(LZO_ABI_NEUTRAL_ENDIAN)
+#if (LZO_ABI_NEUTRAL_ENDIAN)
# define ACC_ABI_NEUTRAL_ENDIAN 1
#endif
-#if defined(LZO_HAVE_CONFIG_H)
+#if (LZO_HAVE_CONFIG_H)
# define ACC_CONFIG_NO_HEADER 1
#endif
#if defined(LZO_CFG_EXTRA_CONFIG_HEADER)
@@ -1886,11 +1930,14 @@ extern "C" {
#endif
#if (LZO_CC_SUNPROC)
+#if !defined(__cplusplus)
# pragma error_messages(off,E_END_OF_LOOP_CODE_NOT_REACHED)
# pragma error_messages(off,E_LOOP_NOT_ENTERED_AT_TOP)
+# pragma error_messages(off,E_STATEMENT_NOT_REACHED)
+#endif
#endif
-#if defined(__LZO_MMODEL_HUGE) && (!LZO_HAVE_MM_HUGE_PTR)
+#if (__LZO_MMODEL_HUGE) && !(LZO_HAVE_MM_HUGE_PTR)
# error "this should not happen - check defines for __huge"
#endif
@@ -1955,40 +2002,44 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
#include <string.h>
#endif
-#if defined(LZO_CFG_FREESTANDING)
+#if (LZO_CFG_FREESTANDING)
# undef HAVE_MEMCMP
# undef HAVE_MEMCPY
# undef HAVE_MEMMOVE
# undef HAVE_MEMSET
#endif
-#if !defined(HAVE_MEMCMP)
+#if !(HAVE_MEMCMP)
# undef memcmp
# define memcmp(a,b,c) lzo_memcmp(a,b,c)
-#elif !defined(__LZO_MMODEL_HUGE)
+#elif !(__LZO_MMODEL_HUGE)
+# undef lzo_memcmp
# define lzo_memcmp(a,b,c) memcmp(a,b,c)
#endif
-#if !defined(HAVE_MEMCPY)
+#if !(HAVE_MEMCPY)
# undef memcpy
# define memcpy(a,b,c) lzo_memcpy(a,b,c)
-#elif !defined(__LZO_MMODEL_HUGE)
+#elif !(__LZO_MMODEL_HUGE)
+# undef lzo_memcpy
# define lzo_memcpy(a,b,c) memcpy(a,b,c)
#endif
-#if !defined(HAVE_MEMMOVE)
+#if !(HAVE_MEMMOVE)
# undef memmove
# define memmove(a,b,c) lzo_memmove(a,b,c)
-#elif !defined(__LZO_MMODEL_HUGE)
+#elif !(__LZO_MMODEL_HUGE)
+# undef lzo_memmove
# define lzo_memmove(a,b,c) memmove(a,b,c)
#endif
-#if !defined(HAVE_MEMSET)
+#if !(HAVE_MEMSET)
# undef memset
# define memset(a,b,c) lzo_memset(a,b,c)
-#elif !defined(__LZO_MMODEL_HUGE)
+#elif !(__LZO_MMODEL_HUGE)
+# undef lzo_memset
# define lzo_memset(a,b,c) memset(a,b,c)
#endif
#undef NDEBUG
-#if defined(LZO_CFG_FREESTANDING)
+#if (LZO_CFG_FREESTANDING)
# undef LZO_DEBUG
# define NDEBUG 1
# undef assert
@@ -2008,13 +2059,24 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
#endif
#if !defined(__lzo_inline)
-# define __lzo_inline
+# define __lzo_inline /*empty*/
#endif
#if !defined(__lzo_forceinline)
-# define __lzo_forceinline
+# define __lzo_forceinline /*empty*/
#endif
#if !defined(__lzo_noinline)
-# define __lzo_noinline
+# define __lzo_noinline /*empty*/
+#endif
+
+#if (LZO_CFG_PGO)
+# undef __acc_likely
+# undef __acc_unlikely
+# undef __lzo_likely
+# undef __lzo_unlikely
+# define __acc_likely(e) (e)
+# define __acc_unlikely(e) (e)
+# define __lzo_likely(e) (e)
+# define __lzo_unlikely(e) (e)
#endif
#if 1
@@ -2050,24 +2112,69 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
#endif
#endif
-#if 1 && !defined(LZO_CFG_NO_UNALIGNED)
-#if 1 && (LZO_ARCH_AMD64 || LZO_ARCH_I386)
+#if 1 && (LZO_ARCH_AMD64 || LZO_ARCH_I386 || LZO_ARCH_POWERPC)
# if (LZO_SIZEOF_SHORT == 2)
-# define LZO_UNALIGNED_OK_2
+# define LZO_UNALIGNED_OK_2 1
# endif
# if (LZO_SIZEOF_INT == 4)
-# define LZO_UNALIGNED_OK_4
+# define LZO_UNALIGNED_OK_4 1
# endif
#endif
+#if 1 && (LZO_ARCH_AMD64)
+# if defined(LZO_UINT64_MAX)
+# define LZO_UNALIGNED_OK_8 1
+# endif
#endif
-
+#if (LZO_CFG_NO_UNALIGNED)
+# undef LZO_UNALIGNED_OK_2
+# undef LZO_UNALIGNED_OK_4
+# undef LZO_UNALIGNED_OK_8
+#endif
+
+#undef UA_GET16
+#undef UA_SET16
+#undef UA_COPY16
+#undef UA_GET32
+#undef UA_SET32
+#undef UA_COPY32
+#undef UA_GET64
+#undef UA_SET64
+#undef UA_COPY64
#if defined(LZO_UNALIGNED_OK_2)
- LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(short) == 2)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(unsigned short) == 2)
+# if 1 && defined(ACC_UA_COPY16)
+# define UA_GET16 ACC_UA_GET16
+# define UA_SET16 ACC_UA_SET16
+# define UA_COPY16 ACC_UA_COPY16
+# else
+# define UA_GET16(p) (* (__lzo_ua_volatile const lzo_ushortp) (__lzo_ua_volatile const lzo_voidp) (p))
+# define UA_SET16(p,v) ((* (__lzo_ua_volatile lzo_ushortp) (__lzo_ua_volatile lzo_voidp) (p)) = (unsigned short) (v))
+# define UA_COPY16(d,s) UA_SET16(d, UA_GET16(s))
+# endif
#endif
-#if defined(LZO_UNALIGNED_OK_4)
- LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4)
-#elif defined(LZO_ALIGNED_OK_4)
- LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4)
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4)
+# if 1 && defined(ACC_UA_COPY32)
+# define UA_GET32 ACC_UA_GET32
+# define UA_SET32 ACC_UA_SET32
+# define UA_COPY32 ACC_UA_COPY32
+# else
+# define UA_GET32(p) (* (__lzo_ua_volatile const lzo_uint32p) (__lzo_ua_volatile const lzo_voidp) (p))
+# define UA_SET32(p,v) ((* (__lzo_ua_volatile lzo_uint32p) (__lzo_ua_volatile lzo_voidp) (p)) = (lzo_uint32) (v))
+# define UA_COPY32(d,s) UA_SET32(d, UA_GET32(s))
+# endif
+#endif
+#if defined(LZO_UNALIGNED_OK_8)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint64) == 8)
+# if 1 && defined(ACC_UA_COPY64)
+# define UA_GET64 ACC_UA_GET64
+# define UA_SET64 ACC_UA_SET64
+# define UA_COPY64 ACC_UA_COPY64
+# else
+# define UA_GET64(p) (* (__lzo_ua_volatile const lzo_uint64p) (__lzo_ua_volatile const lzo_voidp) (p))
+# define UA_SET64(p,v) ((* (__lzo_ua_volatile lzo_uint64p) (__lzo_ua_volatile lzo_voidp) (p)) = (lzo_uint64) (v))
+# define UA_COPY64(d,s) UA_SET64(d, UA_GET64(s))
+# endif
#endif
#define MEMCPY8_DS(dest,src,len) \
@@ -2079,19 +2186,17 @@ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
#define MEMCPY_DS(dest,src,len) \
do *dest++ = *src++; while (--len > 0)
-__LZO_EXTERN_C int __lzo_init_done;
-__LZO_EXTERN_C const char __lzo_copyright[];
LZO_EXTERN(const lzo_bytep) lzo_copyright(void);
#ifndef __LZO_PTR_H
-#define __LZO_PTR_H
+#define __LZO_PTR_H 1
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(lzo_uintptr_t)
-# if defined(__LZO_MMODEL_HUGE)
+# if (__LZO_MMODEL_HUGE)
# define lzo_uintptr_t unsigned long
# else
# define lzo_uintptr_t acc_uintptr_t
@@ -2140,6 +2245,10 @@ typedef union
lzo_uint a_lzo_uint;
lzo_int32 a_lzo_int32;
lzo_uint32 a_lzo_uint32;
+#if defined(LZO_UINT64_MAX)
+ lzo_int64 a_lzo_int64;
+ lzo_uint64 a_lzo_uint64;
+#endif
ptrdiff_t a_ptrdiff_t;
lzo_uintptr_t a_lzo_uintptr_t;
lzo_voidp a_lzo_voidp;
@@ -2161,14 +2270,19 @@ lzo_full_align_t;
#endif
-#define LZO_DETERMINISTIC
+#ifndef LZO_DETERMINISTIC
+#define LZO_DETERMINISTIC 1
+#endif
-#define LZO_DICT_USE_PTR
+#ifndef LZO_DICT_USE_PTR
+#define LZO_DICT_USE_PTR 1
#if 0 && (LZO_ARCH_I086)
# undef LZO_DICT_USE_PTR
+# define LZO_DICT_USE_PTR 0
+#endif
#endif
-#if defined(LZO_DICT_USE_PTR)
+#if (LZO_DICT_USE_PTR)
# define lzo_dict_t const lzo_bytep
# define lzo_dict_p lzo_dict_t __LZO_MMODEL *
#else
@@ -2216,22 +2330,22 @@ __lzo_align_gap(const lzo_voidp ptr, lzo_uint size)
}
#endif
+#if !defined(MINILZO_CFG_SKIP_LZO_UTIL)
/* If you use the LZO library in a product, I would appreciate that you
* keep this copyright string in the executable of your product.
*/
-const char __lzo_copyright[] =
+static const char __lzo_copyright[] =
#if !defined(__LZO_IN_MINLZO)
LZO_VERSION_STRING;
#else
"\r\n\n"
"LZO data compression library.\n"
- "$Copyright: LZO (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Markus Franz Xaver Johannes Oberhumer\n"
+ "$Copyright: LZO Copyright (C) 1996-2011 Markus Franz Xaver Johannes Oberhumer\n"
"<markus@oberhumer.com>\n"
"http://www.oberhumer.com $\n\n"
"$Id: LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE " $\n"
- "$Built: " __DATE__ " " __TIME__ " $\n"
"$Info: " LZO_INFO_STRING " $\n";
#endif
@@ -2321,6 +2435,7 @@ lzo_adler32(lzo_uint32 adler, const lzo_bytep buf, lzo_uint len)
#undef LZO_DO8
#undef LZO_DO16
+#endif
#if !defined(MINILZO_CFG_SKIP_LZO_STRING)
#undef lzo_memcmp
#undef lzo_memcpy
@@ -2343,7 +2458,7 @@ lzo_adler32(lzo_uint32 adler, const lzo_bytep buf, lzo_uint len)
#endif
LZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo_hsize_t len)
{
-#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMCMP)
+#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCMP)
const lzo_hbyte_p p1 = (const lzo_hbyte_p) s1;
const lzo_hbyte_p p2 = (const lzo_hbyte_p) s2;
if __lzo_likely(len > 0) do
@@ -2360,7 +2475,7 @@ LZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo
}
LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len)
{
-#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMCPY)
+#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMCPY)
lzo_hbyte_p p1 = (lzo_hbyte_p) dest;
const lzo_hbyte_p p2 = (const lzo_hbyte_p) src;
if (!(len > 0) || p1 == p2)
@@ -2375,7 +2490,7 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src
}
LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len)
{
-#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMMOVE)
+#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMMOVE)
lzo_hbyte_p p1 = (lzo_hbyte_p) dest;
const lzo_hbyte_p p2 = (const lzo_hbyte_p) src;
if (!(len > 0) || p1 == p2)
@@ -2401,7 +2516,7 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p sr
}
LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len)
{
-#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMSET)
+#if (LZO_HAVE_MM_HUGE_PTR) || !(HAVE_MEMSET)
lzo_hbyte_p p = (lzo_hbyte_p) s;
if __lzo_likely(len > 0) do
*p++ = (unsigned char) c;
@@ -2413,6 +2528,7 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len)
}
#undef LZOLIB_PUBLIC
#endif
+#if !defined(MINILZO_CFG_SKIP_LZO_INIT)
#if !defined(__LZO_IN_MINILZO)
@@ -2426,6 +2542,11 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len)
ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint32)
ACCCHK_ASSERT((LZO_UINT32_C(1) << (int)(8*sizeof(LZO_UINT32_C(1))-1)) > 0)
ACCCHK_ASSERT(sizeof(lzo_uint32) >= 4)
+#if defined(LZO_UINT64_MAX)
+ ACCCHK_ASSERT(sizeof(lzo_uint64) == 8)
+ ACCCHK_ASSERT_IS_SIGNED_T(lzo_int64)
+ ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint64)
+#endif
#if !defined(__LZO_UINTPTR_T_IS_POINTER)
ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uintptr_t)
@@ -2440,40 +2561,158 @@ LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len)
#endif
#undef ACCCHK_ASSERT
+#define WANT_lzo_bitops_clz32 1
+#define WANT_lzo_bitops_clz64 1
+#define WANT_lzo_bitops_ctz32 1
+#define WANT_lzo_bitops_ctz64 1
+
+#if (defined(_WIN32) || defined(_WIN64)) && ((LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_MSC && (_MSC_VER >= 1400)))
+#include <intrin.h>
+#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) && 0
+#pragma intrinsic(_BitScanReverse)
+static __lzo_inline unsigned lzo_bitops_clz32(lzo_uint32 v)
+{
+ unsigned long r;
+ (void) _BitScanReverse(&r, v);
+ return (unsigned) r;
+}
+#define lzo_bitops_clz32 lzo_bitops_clz32
+#endif
+#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) && 0
+#pragma intrinsic(_BitScanReverse64)
+static __lzo_inline unsigned lzo_bitops_clz64(lzo_uint64 v)
+{
+ unsigned long r;
+ (void) _BitScanReverse64(&r, v);
+ return (unsigned) r;
+}
+#define lzo_bitops_clz64 lzo_bitops_clz64
+#endif
+#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32)
+#pragma intrinsic(_BitScanForward)
+static __lzo_inline unsigned lzo_bitops_ctz32(lzo_uint32 v)
+{
+ unsigned long r;
+ (void) _BitScanForward(&r, v);
+ return (unsigned) r;
+}
+#define lzo_bitops_ctz32 lzo_bitops_ctz32
+#endif
+#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX)
+#pragma intrinsic(_BitScanForward64)
+static __lzo_inline unsigned lzo_bitops_ctz64(lzo_uint64 v)
+{
+ unsigned long r;
+ (void) _BitScanForward64(&r, v);
+ return (unsigned) r;
+}
+#define lzo_bitops_ctz64 lzo_bitops_ctz64
+#endif
+
+#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_LLVM && (!defined(__llvm_tools_version__) || (__llvm_tools_version__+0 >= 0x010500ul))))
+#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32)
+#define lzo_bitops_clz32(v) ((unsigned) __builtin_clz(v))
+#endif
+#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_clz64(v) ((unsigned) __builtin_clzll(v))
+#endif
+#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32)
+#define lzo_bitops_ctz32(v) ((unsigned) __builtin_ctz(v))
+#endif
+#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_ctz64(v) ((unsigned) __builtin_ctzll(v))
+#endif
+#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount32)
+#define lzo_bitops_popcount32(v) ((unsigned) __builtin_popcount(v))
+#endif
+#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_popcount64(v) ((unsigned) __builtin_popcountll(v))
+#endif
+#endif
+
+#if 0
+#define u2p(ptr,off) ((lzo_voidp) (((lzo_bytep)(lzo_voidp)(ptr)) + (off)))
+#else
+static __lzo_noinline lzo_voidp u2p(lzo_voidp ptr, lzo_uint off)
+{
+ return (lzo_voidp) ((lzo_bytep) ptr + off);
+}
+#endif
+
LZO_PUBLIC(int)
_lzo_config_check(void)
{
lzo_bool r = 1;
- union { unsigned char c[2*sizeof(lzo_xint)]; lzo_xint l[2]; } u;
- lzo_uintptr_t p;
-
+ union {
+ lzo_xint a[2]; unsigned char b[2*LZO_MAX(8,sizeof(lzo_xint))];
+#if defined(LZO_UNALIGNED_OK_8)
+ lzo_uint64 c[2];
+#endif
+ unsigned short x[2]; lzo_uint32 y[2]; lzo_uint z[2];
+ } u;
+ lzo_voidp p;
+
+ u.a[0] = u.a[1] = 0;
+ p = u2p(&u, 0);
+ r &= ((* (lzo_bytep) p) == 0);
#if !defined(LZO_CFG_NO_CONFIG_CHECK)
#if defined(LZO_ABI_BIG_ENDIAN)
- u.l[0] = u.l[1] = 0; u.c[sizeof(lzo_xint) - 1] = 128;
- r &= (u.l[0] == 128);
+ u.a[0] = u.a[1] = 0; u.b[sizeof(lzo_uint) - 1] = 128;
+ p = u2p(&u, 0);
+ r &= ((* (lzo_uintp) p) == 128);
#endif
#if defined(LZO_ABI_LITTLE_ENDIAN)
- u.l[0] = u.l[1] = 0; u.c[0] = 128;
- r &= (u.l[0] == 128);
+ u.a[0] = u.a[1] = 0; u.b[0] = 128;
+ p = u2p(&u, 0);
+ r &= ((* (lzo_uintp) p) == 128);
#endif
#if defined(LZO_UNALIGNED_OK_2)
- p = (lzo_uintptr_t) (const lzo_voidp) &u.c[0];
- u.l[0] = u.l[1] = 0;
- r &= ((* (const lzo_ushortp) (p+1)) == 0);
+ u.a[0] = u.a[1] = 0;
+ u.b[0] = 1; u.b[sizeof(unsigned short) + 1] = 2;
+ p = u2p(&u, 1);
+ r &= ((* (lzo_ushortp) p) == 0);
#endif
#if defined(LZO_UNALIGNED_OK_4)
- p = (lzo_uintptr_t) (const lzo_voidp) &u.c[0];
- u.l[0] = u.l[1] = 0;
- r &= ((* (const lzo_uint32p) (p+1)) == 0);
+ u.a[0] = u.a[1] = 0;
+ u.b[0] = 3; u.b[sizeof(lzo_uint32) + 1] = 4;
+ p = u2p(&u, 1);
+ r &= ((* (lzo_uint32p) p) == 0);
+#endif
+#if defined(LZO_UNALIGNED_OK_8)
+ u.c[0] = u.c[1] = 0;
+ u.b[0] = 5; u.b[sizeof(lzo_uint64) + 1] = 6;
+ p = u2p(&u, 1);
+ r &= ((* (lzo_uint64p) p) == 0);
+#endif
+#if defined(lzo_bitops_clz32)
+ { unsigned i; lzo_uint32 v = 1;
+ for (i = 0; i < 32; i++, v <<= 1)
+ r &= lzo_bitops_clz32(v) == 31 - i;
+ }
+#endif
+#if defined(lzo_bitops_clz64)
+ { unsigned i; lzo_uint64 v = 1;
+ for (i = 0; i < 64; i++, v <<= 1)
+ r &= lzo_bitops_clz64(v) == 63 - i;
+ }
+#endif
+#if defined(lzo_bitops_ctz32)
+ { unsigned i; lzo_uint32 v = 1;
+ for (i = 0; i < 32; i++, v <<= 1)
+ r &= lzo_bitops_ctz32(v) == i;
+ }
+#endif
+#if defined(lzo_bitops_ctz64)
+ { unsigned i; lzo_uint64 v = 1;
+ for (i = 0; i < 64; i++, v <<= 1)
+ r &= lzo_bitops_ctz64(v) == i;
+ }
#endif
#endif
- LZO_UNUSED(u); LZO_UNUSED(p);
return r == 1 ? LZO_E_OK : LZO_E_ERROR;
}
-int __lzo_init_done = 0;
-
LZO_PUBLIC(int)
__lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5,
int s6, int s7, int s8, int s9)
@@ -2489,8 +2728,6 @@ __lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5,
#endif
#undef ACCCHK_ASSERT
- __lzo_init_done = 1;
-
if (v == 0)
return LZO_E_ERROR;
@@ -2532,27 +2769,47 @@ int __far __pascal LibMain ( int a, short b, short c, long d )
#endif
-#define do_compress _lzo1x_1_do_compress
+#endif
+
+#define LZO1X 1
+#define LZO_EOF_CODE 1
+#define M2_MAX_OFFSET 0x0800
#if !defined(MINILZO_CFG_SKIP_LZO1X_1_COMPRESS)
-#define LZO_NEED_DICT_H
+#if 1 && defined(UA_GET32)
+#undef LZO_DICT_USE_PTR
+#define LZO_DICT_USE_PTR 0
+#undef lzo_dict_t
+#define lzo_dict_t unsigned short
+#endif
+
+#define LZO_NEED_DICT_H 1
+#ifndef D_BITS
#define D_BITS 14
+#endif
#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5)
#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
+#if 1
+#define DINDEX(dv,p) DM(((DMUL(0x1824429d,dv)) >> (32-D_BITS)))
+#else
+#define DINDEX(dv,p) DM((dv) + ((dv) >> (32-D_BITS)))
+#endif
#ifndef __LZO_CONFIG1X_H
-#define __LZO_CONFIG1X_H
+#define __LZO_CONFIG1X_H 1
#if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z)
-# define LZO1X
+# define LZO1X 1
#endif
#if !defined(__LZO_IN_MINILZO)
#include "lzo/lzo1x.h"
#endif
-#define LZO_EOF_CODE
+#ifndef LZO_EOF_CODE
+#define LZO_EOF_CODE 1
+#endif
#undef LZO_DETERMINISTIC
#define M1_MAX_OFFSET 0x0400
@@ -2592,7 +2849,7 @@ int __far __pascal LibMain ( int a, short b, short c, long d )
#define DL_MIN_LEN M2_MIN_LEN
#ifndef __LZO_DICT_H
-#define __LZO_DICT_H
+#define __LZO_DICT_H 1
#ifdef __cplusplus
extern "C" {
@@ -2633,10 +2890,10 @@ extern "C" {
#if (D_BITS != DL_BITS + DD_BITS)
# error "D_BITS does not match"
#endif
-#if (D_BITS < 8 || D_BITS > 18)
+#if (D_BITS < 6 || D_BITS > 18)
# error "invalid D_BITS"
#endif
-#if (DL_BITS < 8 || DL_BITS > 20)
+#if (DL_BITS < 6 || DL_BITS > 20)
# error "invalid DL_BITS"
#endif
#if (DD_BITS < 0 || DD_BITS > 6)
@@ -2695,14 +2952,14 @@ extern "C" {
# define _DINDEX(dv,p) (_DV_A((p),DL_SHIFT))
#elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL)
-# define __LZO_HASH_INCREMENTAL
+# define __LZO_HASH_INCREMENTAL 1
# define DVAL_FIRST(dv,p) dv = _DV_A((p),DL_SHIFT)
# define DVAL_NEXT(dv,p) dv = (((dv) << DL_SHIFT) ^ p[2])
# define _DINDEX(dv,p) (dv)
# define DVAL_LOOKAHEAD DL_MIN_LEN
#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A)
-# define __LZO_HASH_INCREMENTAL
+# define __LZO_HASH_INCREMENTAL 1
# define DVAL_FIRST(dv,p) dv = _DV_A((p),5)
# define DVAL_NEXT(dv,p) \
dv ^= (lzo_xint)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2])
@@ -2710,7 +2967,7 @@ extern "C" {
# define DVAL_LOOKAHEAD DL_MIN_LEN
#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B)
-# define __LZO_HASH_INCREMENTAL
+# define __LZO_HASH_INCREMENTAL 1
# define DVAL_FIRST(dv,p) dv = _DV_B((p),5)
# define DVAL_NEXT(dv,p) \
dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_xint)(p[2]) << (2*5)))
@@ -2739,7 +2996,12 @@ extern "C" {
#if !defined(DVAL_ASSERT)
#if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG)
-static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
+#if (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x020700ul) || LZO_CC_LLVM)
+static void __attribute__((__unused__))
+#else
+static void
+#endif
+DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
{
lzo_xint df;
DVAL_FIRST(df,(p));
@@ -2750,11 +3012,11 @@ static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
#endif
#endif
-#if defined(LZO_DICT_USE_PTR)
+#if (LZO_DICT_USE_PTR)
# define DENTRY(p,in) (p)
# define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex]
#else
-# define DENTRY(p,in) ((lzo_uint) ((p)-(in)))
+# define DENTRY(p,in) ((lzo_dict_t) pd(p, in))
# define GINDEX(m_pos,m_off,dict,dindex,in) m_off = dict[dindex]
#endif
@@ -2775,7 +3037,7 @@ static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
#endif
-#if defined(LZO_DICT_USE_PTR)
+#if (LZO_DICT_USE_PTR)
#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
(m_pos == NULL || (m_off = pd(ip, m_pos)) > max_offset)
@@ -2784,7 +3046,7 @@ static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
(BOUNDS_CHECKING_OFF_IN_EXPR(( \
m_pos = ip - (lzo_uint) PTR_DIFF(ip,m_pos), \
PTR_LT(m_pos,in) || \
- (m_off = (lzo_uint) PTR_DIFF(ip,m_pos)) <= 0 || \
+ (m_off = (lzo_uint) PTR_DIFF(ip,m_pos)) == 0 || \
m_off > max_offset )))
#else
@@ -2801,7 +3063,7 @@ static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
#endif
-#if defined(LZO_DETERMINISTIC)
+#if (LZO_DETERMINISTIC)
# define LZO_CHECK_MPOS LZO_CHECK_MPOS_DET
#else
# define LZO_CHECK_MPOS LZO_CHECK_MPOS_NON_DET
@@ -2817,17 +3079,99 @@ static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
#endif
+#define LZO_DETERMINISTIC !(LZO_DICT_USE_PTR)
+
+#ifndef DO_COMPRESS
#define DO_COMPRESS lzo1x_1_compress
+#endif
+
+#if 1 && defined(DO_COMPRESS) && !defined(do_compress)
+# define do_compress LZO_CPP_ECONCAT2(DO_COMPRESS,_core)
+#endif
+
+#if defined(UA_GET64) && (LZO_ABI_BIG_ENDIAN)
+# define WANT_lzo_bitops_clz64 1
+#elif defined(UA_GET64) && (LZO_ABI_LITTLE_ENDIAN)
+# define WANT_lzo_bitops_ctz64 1
+#elif defined(UA_GET32) && (LZO_ABI_BIG_ENDIAN)
+# define WANT_lzo_bitops_clz32 1
+#elif defined(UA_GET32) && (LZO_ABI_LITTLE_ENDIAN)
+# define WANT_lzo_bitops_ctz32 1
+#endif
+
+#if (defined(_WIN32) || defined(_WIN64)) && ((LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_MSC && (_MSC_VER >= 1400)))
+#include <intrin.h>
+#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32) && 0
+#pragma intrinsic(_BitScanReverse)
+static __lzo_inline unsigned lzo_bitops_clz32(lzo_uint32 v)
+{
+ unsigned long r;
+ (void) _BitScanReverse(&r, v);
+ return (unsigned) r;
+}
+#define lzo_bitops_clz32 lzo_bitops_clz32
+#endif
+#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX) && 0
+#pragma intrinsic(_BitScanReverse64)
+static __lzo_inline unsigned lzo_bitops_clz64(lzo_uint64 v)
+{
+ unsigned long r;
+ (void) _BitScanReverse64(&r, v);
+ return (unsigned) r;
+}
+#define lzo_bitops_clz64 lzo_bitops_clz64
+#endif
+#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32)
+#pragma intrinsic(_BitScanForward)
+static __lzo_inline unsigned lzo_bitops_ctz32(lzo_uint32 v)
+{
+ unsigned long r;
+ (void) _BitScanForward(&r, v);
+ return (unsigned) r;
+}
+#define lzo_bitops_ctz32 lzo_bitops_ctz32
+#endif
+#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX)
+#pragma intrinsic(_BitScanForward64)
+static __lzo_inline unsigned lzo_bitops_ctz64(lzo_uint64 v)
+{
+ unsigned long r;
+ (void) _BitScanForward64(&r, v);
+ return (unsigned) r;
+}
+#define lzo_bitops_ctz64 lzo_bitops_ctz64
+#endif
+
+#elif (LZO_CC_CLANG || (LZO_CC_GNUC >= 0x030400ul) || (LZO_CC_INTELC && (__INTEL_COMPILER >= 1000)) || (LZO_CC_LLVM && (!defined(__llvm_tools_version__) || (__llvm_tools_version__+0 >= 0x010500ul))))
+#if !defined(lzo_bitops_clz32) && defined(WANT_lzo_bitops_clz32)
+#define lzo_bitops_clz32(v) ((unsigned) __builtin_clz(v))
+#endif
+#if !defined(lzo_bitops_clz64) && defined(WANT_lzo_bitops_clz64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_clz64(v) ((unsigned) __builtin_clzll(v))
+#endif
+#if !defined(lzo_bitops_ctz32) && defined(WANT_lzo_bitops_ctz32)
+#define lzo_bitops_ctz32(v) ((unsigned) __builtin_ctz(v))
+#endif
+#if !defined(lzo_bitops_ctz64) && defined(WANT_lzo_bitops_ctz64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_ctz64(v) ((unsigned) __builtin_ctzll(v))
+#endif
+#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount32)
+#define lzo_bitops_popcount32(v) ((unsigned) __builtin_popcount(v))
+#endif
+#if !defined(lzo_bitops_popcount32) && defined(WANT_lzo_bitops_popcount64) && defined(LZO_UINT64_MAX)
+#define lzo_bitops_popcount64(v) ((unsigned) __builtin_popcountll(v))
+#endif
+#endif
static __lzo_noinline lzo_uint
do_compress ( const lzo_bytep in , lzo_uint in_len,
lzo_bytep out, lzo_uintp out_len,
- lzo_voidp wrkmem )
+ lzo_uint ti, lzo_voidp wrkmem)
{
register const lzo_bytep ip;
lzo_bytep op;
const lzo_bytep const in_end = in + in_len;
- const lzo_bytep const ip_end = in + in_len - M2_MAX_LEN - 5;
+ const lzo_bytep const ip_end = in + in_len - 20;
const lzo_bytep ii;
lzo_dict_p const dict = (lzo_dict_p) wrkmem;
@@ -2835,14 +3179,17 @@ do_compress ( const lzo_bytep in , lzo_uint in_len,
ip = in;
ii = ip;
- ip += 4;
+ ip += ti < 4 ? 4 - ti : 0;
for (;;)
{
- register const lzo_bytep m_pos;
- lzo_uint m_off;
+ const lzo_bytep m_pos;
+#if !(LZO_DETERMINISTIC)
+ LZO_DEFINE_UNINITIALIZED_VAR(lzo_uint, m_off, 0);
lzo_uint m_len;
lzo_uint dindex;
-
+next:
+ if __lzo_unlikely(ip >= ip_end)
+ break;
DINDEX1(dindex,ip);
GINDEX(m_pos,m_off,dict,dindex,in);
if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
@@ -2860,200 +3207,245 @@ do_compress ( const lzo_bytep in , lzo_uint in_len,
goto literal;
try_match:
-#if 1 && defined(LZO_UNALIGNED_OK_2)
- if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip)
+#if defined(UA_GET32)
+ if (UA_GET32(m_pos) != UA_GET32(ip))
#else
- if (m_pos[0] != ip[0] || m_pos[1] != ip[1])
+ if (m_pos[0] != ip[0] || m_pos[1] != ip[1] || m_pos[2] != ip[2] || m_pos[3] != ip[3])
#endif
{
+literal:
+ UPDATE_I(dict,0,dindex,ip,in);
+ ip += 1 + ((ip - ii) >> 5);
+ continue;
}
- else
- {
- if __lzo_likely(m_pos[2] == ip[2])
- {
-#if 0
- if (m_off <= M2_MAX_OFFSET)
- goto match;
- if (lit <= 3)
- goto match;
- if (lit == 3)
- {
- assert(op - 2 > out); op[-2] |= LZO_BYTE(3);
- *op++ = *ii++; *op++ = *ii++; *op++ = *ii++;
- goto code_match;
- }
- if (m_pos[3] == ip[3])
-#endif
- goto match;
- }
- else
- {
-#if 0
-#if 0
- if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3)
+ UPDATE_I(dict,0,dindex,ip,in);
#else
- if (m_off <= M1_MAX_OFFSET && lit == 3)
-#endif
- {
- register lzo_uint t;
-
- t = lit;
- assert(op - 2 > out); op[-2] |= LZO_BYTE(t);
- do *op++ = *ii++; while (--t > 0);
- assert(ii == ip);
- m_off -= 1;
- *op++ = LZO_BYTE(M1_MARKER | ((m_off & 3) << 2));
- *op++ = LZO_BYTE(m_off >> 2);
- ip += 2;
- goto match_done;
- }
-#endif
- }
- }
-
+ lzo_uint m_off;
+ lzo_uint m_len;
+ {
+ lzo_uint32 dv;
+ lzo_uint dindex;
literal:
- UPDATE_I(dict,0,dindex,ip,in);
- ++ip;
+ ip += 1 + ((ip - ii) >> 5);
+next:
if __lzo_unlikely(ip >= ip_end)
break;
- continue;
-
-match:
+ dv = UA_GET32(ip);
+ dindex = DINDEX(dv,ip);
+ GINDEX(m_off,m_pos,in+dict,dindex,in);
UPDATE_I(dict,0,dindex,ip,in);
- if (pd(ip,ii) > 0)
- {
- register lzo_uint t = pd(ip,ii);
+ if __lzo_unlikely(dv != UA_GET32(m_pos))
+ goto literal;
+ }
+#endif
+ ii -= ti; ti = 0;
+ {
+ register lzo_uint t = pd(ip,ii);
+ if (t != 0)
+ {
if (t <= 3)
{
- assert(op - 2 > out);
op[-2] |= LZO_BYTE(t);
+#if defined(UA_COPY32)
+ UA_COPY32(op, ii);
+ op += t;
+#else
+ { do *op++ = *ii++; while (--t > 0); }
+#endif
}
- else if (t <= 18)
+#if defined(UA_COPY32) || defined(UA_COPY64)
+ else if (t <= 16)
+ {
*op++ = LZO_BYTE(t - 3);
+#if defined(UA_COPY64)
+ UA_COPY64(op, ii);
+ UA_COPY64(op+8, ii+8);
+#else
+ UA_COPY32(op, ii);
+ UA_COPY32(op+4, ii+4);
+ UA_COPY32(op+8, ii+8);
+ UA_COPY32(op+12, ii+12);
+#endif
+ op += t;
+ }
+#endif
else
{
- register lzo_uint tt = t - 18;
-
- *op++ = 0;
- while (tt > 255)
+ if (t <= 18)
+ *op++ = LZO_BYTE(t - 3);
+ else
{
- tt -= 255;
+ register lzo_uint tt = t - 18;
*op++ = 0;
+ while __lzo_unlikely(tt > 255)
+ {
+ tt -= 255;
+#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400))
+ * (volatile unsigned char *) op++ = 0;
+#else
+ *op++ = 0;
+#endif
+ }
+ assert(tt > 0);
+ *op++ = LZO_BYTE(tt);
}
- assert(tt > 0);
- *op++ = LZO_BYTE(tt);
+#if defined(UA_COPY32) || defined(UA_COPY64)
+ do {
+#if defined(UA_COPY64)
+ UA_COPY64(op, ii);
+ UA_COPY64(op+8, ii+8);
+#else
+ UA_COPY32(op, ii);
+ UA_COPY32(op+4, ii+4);
+ UA_COPY32(op+8, ii+8);
+ UA_COPY32(op+12, ii+12);
+#endif
+ op += 16; ii += 16; t -= 16;
+ } while (t >= 16); if (t > 0)
+#endif
+ { do *op++ = *ii++; while (--t > 0); }
}
- do *op++ = *ii++; while (--t > 0);
}
-
- assert(ii == ip);
- ip += 3;
- if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ ||
- m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++
-#ifdef LZO1Y
- || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++
- || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++
+ }
+ m_len = 4;
+ {
+#if defined(UA_GET64)
+ lzo_uint64 v;
+ v = UA_GET64(ip + m_len) ^ UA_GET64(m_pos + m_len);
+ if __lzo_unlikely(v == 0) {
+ do {
+ m_len += 8;
+ v = UA_GET64(ip + m_len) ^ UA_GET64(m_pos + m_len);
+ if __lzo_unlikely(ip + m_len >= ip_end)
+ goto m_len_done;
+ } while (v == 0);
+ }
+#if (LZO_ABI_BIG_ENDIAN) && defined(lzo_bitops_clz64)
+ m_len += lzo_bitops_clz64(v) / CHAR_BIT;
+#elif (LZO_ABI_BIG_ENDIAN)
+ if ((v >> (64 - CHAR_BIT)) == 0) do {
+ v <<= CHAR_BIT;
+ m_len += 1;
+ } while ((v >> (64 - CHAR_BIT)) == 0);
+#elif (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_ctz64)
+ m_len += lzo_bitops_ctz64(v) / CHAR_BIT;
+#elif (LZO_ABI_LITTLE_ENDIAN)
+ if ((v & UCHAR_MAX) == 0) do {
+ v >>= CHAR_BIT;
+ m_len += 1;
+ } while ((v & UCHAR_MAX) == 0);
+#else
+ if (ip[m_len] == m_pos[m_len]) do {
+ m_len += 1;
+ } while (ip[m_len] == m_pos[m_len]);
+#endif
+#elif defined(UA_GET32)
+ lzo_uint32 v;
+ v = UA_GET32(ip + m_len) ^ UA_GET32(m_pos + m_len);
+ if __lzo_unlikely(v == 0) {
+ do {
+ m_len += 4;
+ v = UA_GET32(ip + m_len) ^ UA_GET32(m_pos + m_len);
+ if __lzo_unlikely(ip + m_len >= ip_end)
+ goto m_len_done;
+ } while (v == 0);
+ }
+#if (LZO_ABI_BIG_ENDIAN) && defined(lzo_bitops_clz32)
+ m_len += lzo_bitops_clz32(v) / CHAR_BIT;
+#elif (LZO_ABI_BIG_ENDIAN)
+ if ((v >> (32 - CHAR_BIT)) == 0) do {
+ v <<= CHAR_BIT;
+ m_len += 1;
+ } while ((v >> (32 - CHAR_BIT)) == 0);
+#elif (LZO_ABI_LITTLE_ENDIAN) && defined(lzo_bitops_ctz32)
+ m_len += lzo_bitops_ctz32(v) / CHAR_BIT;
+#elif (LZO_ABI_LITTLE_ENDIAN)
+ if ((v & UCHAR_MAX) == 0) do {
+ v >>= CHAR_BIT;
+ m_len += 1;
+ } while ((v & UCHAR_MAX) == 0);
+#else
+ if (ip[m_len] == m_pos[m_len]) do {
+ m_len += 1;
+ } while (ip[m_len] == m_pos[m_len]);
+#endif
+#else
+ if __lzo_unlikely(ip[m_len] == m_pos[m_len]) {
+ do {
+ m_len += 1;
+ if __lzo_unlikely(ip + m_len >= ip_end)
+ goto m_len_done;
+ } while (ip[m_len] == m_pos[m_len]);
+ }
#endif
- )
+ }
+m_len_done:
+ m_off = pd(ip,m_pos);
+ ip += m_len;
+ ii = ip;
+ if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)
{
- --ip;
- m_len = pd(ip, ii);
- assert(m_len >= 3); assert(m_len <= M2_MAX_LEN);
-
- if (m_off <= M2_MAX_OFFSET)
- {
- m_off -= 1;
+ m_off -= 1;
#if defined(LZO1X)
- *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2));
- *op++ = LZO_BYTE(m_off >> 3);
+ *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2));
+ *op++ = LZO_BYTE(m_off >> 3);
#elif defined(LZO1Y)
- *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2));
- *op++ = LZO_BYTE(m_off >> 2);
+ *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2));
+ *op++ = LZO_BYTE(m_off >> 2);
#endif
- }
- else if (m_off <= M3_MAX_OFFSET)
- {
- m_off -= 1;
+ }
+ else if (m_off <= M3_MAX_OFFSET)
+ {
+ m_off -= 1;
+ if (m_len <= M3_MAX_LEN)
*op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
- goto m3_m4_offset;
- }
else
-#if defined(LZO1X)
{
- m_off -= 0x4000;
- assert(m_off > 0); assert(m_off <= 0x7fff);
- *op++ = LZO_BYTE(M4_MARKER |
- ((m_off & 0x4000) >> 11) | (m_len - 2));
- goto m3_m4_offset;
- }
-#elif defined(LZO1Y)
- goto m4_match;
+ m_len -= M3_MAX_LEN;
+ *op++ = M3_MARKER | 0;
+ while __lzo_unlikely(m_len > 255)
+ {
+ m_len -= 255;
+#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400))
+ * (volatile unsigned char *) op++ = 0;
+#else
+ *op++ = 0;
#endif
+ }
+ *op++ = LZO_BYTE(m_len);
+ }
+ *op++ = LZO_BYTE(m_off << 2);
+ *op++ = LZO_BYTE(m_off >> 6);
}
else
{
- {
- const lzo_bytep end = in_end;
- const lzo_bytep m = m_pos + M2_MAX_LEN + 1;
- while (ip < end && *m == *ip)
- m++, ip++;
- m_len = pd(ip, ii);
- }
- assert(m_len > M2_MAX_LEN);
-
- if (m_off <= M3_MAX_OFFSET)
- {
- m_off -= 1;
- if (m_len <= 33)
- *op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
- else
- {
- m_len -= 33;
- *op++ = M3_MARKER | 0;
- goto m3_m4_len;
- }
- }
+ m_off -= 0x4000;
+ if (m_len <= M4_MAX_LEN)
+ *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8) | (m_len - 2));
else
{
-#if defined(LZO1Y)
-m4_match:
-#endif
- m_off -= 0x4000;
- assert(m_off > 0); assert(m_off <= 0x7fff);
- if (m_len <= M4_MAX_LEN)
- *op++ = LZO_BYTE(M4_MARKER |
- ((m_off & 0x4000) >> 11) | (m_len - 2));
- else
+ m_len -= M4_MAX_LEN;
+ *op++ = LZO_BYTE(M4_MARKER | ((m_off >> 11) & 8));
+ while __lzo_unlikely(m_len > 255)
{
- m_len -= M4_MAX_LEN;
- *op++ = LZO_BYTE(M4_MARKER | ((m_off & 0x4000) >> 11));
-m3_m4_len:
- while (m_len > 255)
- {
- m_len -= 255;
- *op++ = 0;
- }
- assert(m_len > 0);
- *op++ = LZO_BYTE(m_len);
+ m_len -= 255;
+#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400))
+ * (volatile unsigned char *) op++ = 0;
+#else
+ *op++ = 0;
+#endif
}
+ *op++ = LZO_BYTE(m_len);
}
-
-m3_m4_offset:
- *op++ = LZO_BYTE((m_off & 63) << 2);
+ *op++ = LZO_BYTE(m_off << 2);
*op++ = LZO_BYTE(m_off >> 6);
}
-
-#if 0
-match_done:
-#endif
- ii = ip;
- if __lzo_unlikely(ip >= ip_end)
- break;
+ goto next;
}
*out_len = pd(op, out);
- return pd(in_end,ii);
+ return pd(in_end,ii-ti);
}
LZO_PUBLIC(int)
@@ -3061,16 +3453,30 @@ DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len,
lzo_bytep out, lzo_uintp out_len,
lzo_voidp wrkmem )
{
+ const lzo_bytep ip = in;
lzo_bytep op = out;
- lzo_uint t;
+ lzo_uint l = in_len;
+ lzo_uint t = 0;
- if __lzo_unlikely(in_len <= M2_MAX_LEN + 5)
- t = in_len;
- else
+ while (l > 20)
{
- t = do_compress(in,in_len,op,out_len,wrkmem);
+ lzo_uint ll = l;
+ lzo_uintptr_t ll_end;
+#if 0 || (LZO_DETERMINISTIC)
+ ll = LZO_MIN(ll, 49152);
+#endif
+ ll_end = (lzo_uintptr_t)ip + ll;
+ if ((ll_end + ((t + ll) >> 5)) <= ll_end || (const lzo_bytep)(ll_end + ((t + ll) >> 5)) <= ip + ll)
+ break;
+#if (LZO_DETERMINISTIC)
+ lzo_memset(wrkmem, 0, ((lzo_uint)1 << D_BITS) * sizeof(lzo_dict_t));
+#endif
+ t = do_compress(ip,ll,op,out_len,t,wrkmem);
+ ip += ll;
op += *out_len;
+ l -= ll;
}
+ t += l;
if (t > 0)
{
@@ -3090,7 +3496,12 @@ DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len,
while (tt > 255)
{
tt -= 255;
+#if 1 && (LZO_CC_MSC && (_MSC_VER >= 1400))
+
+ * (volatile unsigned char *) op++ = 0;
+#else
*op++ = 0;
+#endif
}
assert(tt > 0);
*op++ = LZO_BYTE(tt);
@@ -3126,7 +3537,7 @@ DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len,
# define LZO_TEST_OVERRUN_OUTPUT 2
# endif
# if !defined(LZO_TEST_OVERRUN_LOOKBEHIND)
-# define LZO_TEST_OVERRUN_LOOKBEHIND
+# define LZO_TEST_OVERRUN_LOOKBEHIND 1
# endif
#endif
@@ -3177,42 +3588,32 @@ DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len,
#endif
#if defined(TEST_IP)
-# define HAVE_TEST_IP
+# define HAVE_TEST_IP 1
#else
# define TEST_IP 1
#endif
#if defined(TEST_OP)
-# define HAVE_TEST_OP
+# define HAVE_TEST_OP 1
#else
# define TEST_OP 1
#endif
#if defined(NEED_IP)
-# define HAVE_NEED_IP
+# define HAVE_NEED_IP 1
#else
# define NEED_IP(x) ((void) 0)
#endif
#if defined(NEED_OP)
-# define HAVE_NEED_OP
+# define HAVE_NEED_OP 1
#else
# define NEED_OP(x) ((void) 0)
#endif
#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
-# define HAVE_ANY_IP
+# define HAVE_ANY_IP 1
#endif
#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
-# define HAVE_ANY_OP
-#endif
-
-#undef __COPY4
-#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
-
-#undef COPY4
-#if defined(LZO_UNALIGNED_OK_4)
-# define COPY4(dst,src) __COPY4(dst,src)
-#elif defined(LZO_ALIGNED_OK_4)
-# define COPY4(dst,src) __COPY4((lzo_uintptr_t)(dst),(lzo_uintptr_t)(src))
+# define HAVE_ANY_OP 1
#endif
#if defined(DO_DECOMPRESS)
@@ -3291,19 +3692,36 @@ DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len,
t += 15 + *ip++;
}
assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
-#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4)
+ t += 3;
+ if (t >= 8) do
+ {
+ UA_COPY64(op,ip);
+ op += 8; ip += 8; t -= 8;
+ } while (t >= 8);
+ if (t >= 4)
+ {
+ UA_COPY32(op,ip);
+ op += 4; ip += 4; t -= 4;
+ }
+ if (t > 0)
+ {
+ *op++ = *ip++;
+ if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
+ }
+#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
#if !defined(LZO_UNALIGNED_OK_4)
if (PTR_ALIGNED2_4(op,ip))
{
#endif
- COPY4(op,ip);
+ UA_COPY32(op,ip);
op += 4; ip += 4;
if (--t > 0)
{
if (t >= 4)
{
do {
- COPY4(op,ip);
+ UA_COPY32(op,ip);
op += 4; ip += 4; t -= 4;
} while (t >= 4);
if (t > 0) do *op++ = *ip++; while (--t > 0);
@@ -3316,7 +3734,7 @@ DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len,
else
#endif
#endif
-#if !defined(LZO_UNALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4) && !defined(LZO_UNALIGNED_OK_8)
{
*op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
do *op++ = *ip++; while (--t > 0);
@@ -3437,7 +3855,7 @@ match:
}
#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
m_pos = op - 1;
- m_pos -= (* (const lzo_ushortp) ip) >> 2;
+ m_pos -= UA_GET16(ip) >> 2;
#else
m_pos = op - 1;
m_pos -= (ip[0] >> 2) + (ip[1] << 6);
@@ -3482,7 +3900,7 @@ match:
#if defined(LZO1Z)
m_pos -= (ip[0] << 6) + (ip[1] >> 2);
#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
- m_pos -= (* (const lzo_ushortp) ip) >> 2;
+ m_pos -= UA_GET16(ip) >> 2;
#else
m_pos -= (ip[0] >> 2) + (ip[1] << 6);
#endif
@@ -3530,7 +3948,28 @@ match:
#else
TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
-#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4)
+ if (op - m_pos >= 8)
+ {
+ t += (3 - 1);
+ if (t >= 8) do
+ {
+ UA_COPY64(op,m_pos);
+ op += 8; m_pos += 8; t -= 8;
+ } while (t >= 8);
+ if (t >= 4)
+ {
+ UA_COPY32(op,m_pos);
+ op += 4; m_pos += 4; t -= 4;
+ }
+ if (t > 0)
+ {
+ *op++ = m_pos[0];
+ if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } }
+ }
+ }
+ else
+#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
#if !defined(LZO_UNALIGNED_OK_4)
if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
{
@@ -3539,10 +3978,10 @@ match:
if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
{
#endif
- COPY4(op,m_pos);
+ UA_COPY32(op,m_pos);
op += 4; m_pos += 4; t -= 4 - (3 - 1);
do {
- COPY4(op,m_pos);
+ UA_COPY32(op,m_pos);
op += 4; m_pos += 4; t -= 4;
} while (t >= 4);
if (t > 0) do *op++ = *m_pos++; while (--t > 0);
@@ -3610,7 +4049,7 @@ lookbehind_overrun:
#endif
-#define LZO_TEST_OVERRUN
+#define LZO_TEST_OVERRUN 1
#undef DO_DECOMPRESS
#define DO_DECOMPRESS lzo1x_decompress_safe
@@ -3624,7 +4063,7 @@ lookbehind_overrun:
# define LZO_TEST_OVERRUN_OUTPUT 2
# endif
# if !defined(LZO_TEST_OVERRUN_LOOKBEHIND)
-# define LZO_TEST_OVERRUN_LOOKBEHIND
+# define LZO_TEST_OVERRUN_LOOKBEHIND 1
# endif
#endif
@@ -3675,42 +4114,32 @@ lookbehind_overrun:
#endif
#if defined(TEST_IP)
-# define HAVE_TEST_IP
+# define HAVE_TEST_IP 1
#else
# define TEST_IP 1
#endif
#if defined(TEST_OP)
-# define HAVE_TEST_OP
+# define HAVE_TEST_OP 1
#else
# define TEST_OP 1
#endif
#if defined(NEED_IP)
-# define HAVE_NEED_IP
+# define HAVE_NEED_IP 1
#else
# define NEED_IP(x) ((void) 0)
#endif
#if defined(NEED_OP)
-# define HAVE_NEED_OP
+# define HAVE_NEED_OP 1
#else
# define NEED_OP(x) ((void) 0)
#endif
#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
-# define HAVE_ANY_IP
+# define HAVE_ANY_IP 1
#endif
#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
-# define HAVE_ANY_OP
-#endif
-
-#undef __COPY4
-#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
-
-#undef COPY4
-#if defined(LZO_UNALIGNED_OK_4)
-# define COPY4(dst,src) __COPY4(dst,src)
-#elif defined(LZO_ALIGNED_OK_4)
-# define COPY4(dst,src) __COPY4((lzo_uintptr_t)(dst),(lzo_uintptr_t)(src))
+# define HAVE_ANY_OP 1
#endif
#if defined(DO_DECOMPRESS)
@@ -3789,19 +4218,36 @@ DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len,
t += 15 + *ip++;
}
assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
-#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4)
+ t += 3;
+ if (t >= 8) do
+ {
+ UA_COPY64(op,ip);
+ op += 8; ip += 8; t -= 8;
+ } while (t >= 8);
+ if (t >= 4)
+ {
+ UA_COPY32(op,ip);
+ op += 4; ip += 4; t -= 4;
+ }
+ if (t > 0)
+ {
+ *op++ = *ip++;
+ if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
+ }
+#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
#if !defined(LZO_UNALIGNED_OK_4)
if (PTR_ALIGNED2_4(op,ip))
{
#endif
- COPY4(op,ip);
+ UA_COPY32(op,ip);
op += 4; ip += 4;
if (--t > 0)
{
if (t >= 4)
{
do {
- COPY4(op,ip);
+ UA_COPY32(op,ip);
op += 4; ip += 4; t -= 4;
} while (t >= 4);
if (t > 0) do *op++ = *ip++; while (--t > 0);
@@ -3814,7 +4260,7 @@ DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len,
else
#endif
#endif
-#if !defined(LZO_UNALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4) && !defined(LZO_UNALIGNED_OK_8)
{
*op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
do *op++ = *ip++; while (--t > 0);
@@ -3935,7 +4381,7 @@ match:
}
#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
m_pos = op - 1;
- m_pos -= (* (const lzo_ushortp) ip) >> 2;
+ m_pos -= UA_GET16(ip) >> 2;
#else
m_pos = op - 1;
m_pos -= (ip[0] >> 2) + (ip[1] << 6);
@@ -3980,7 +4426,7 @@ match:
#if defined(LZO1Z)
m_pos -= (ip[0] << 6) + (ip[1] >> 2);
#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
- m_pos -= (* (const lzo_ushortp) ip) >> 2;
+ m_pos -= UA_GET16(ip) >> 2;
#else
m_pos -= (ip[0] >> 2) + (ip[1] << 6);
#endif
@@ -4028,7 +4474,28 @@ match:
#else
TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
-#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if defined(LZO_UNALIGNED_OK_8) && defined(LZO_UNALIGNED_OK_4)
+ if (op - m_pos >= 8)
+ {
+ t += (3 - 1);
+ if (t >= 8) do
+ {
+ UA_COPY64(op,m_pos);
+ op += 8; m_pos += 8; t -= 8;
+ } while (t >= 8);
+ if (t >= 4)
+ {
+ UA_COPY32(op,m_pos);
+ op += 4; m_pos += 4; t -= 4;
+ }
+ if (t > 0)
+ {
+ *op++ = m_pos[0];
+ if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } }
+ }
+ }
+ else
+#elif defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
#if !defined(LZO_UNALIGNED_OK_4)
if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
{
@@ -4037,10 +4504,10 @@ match:
if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
{
#endif
- COPY4(op,m_pos);
+ UA_COPY32(op,m_pos);
op += 4; m_pos += 4; t -= 4 - (3 - 1);
do {
- COPY4(op,m_pos);
+ UA_COPY32(op,m_pos);
op += 4; m_pos += 4; t -= 4;
} while (t >= 4);
if (t > 0) do *op++ = *m_pos++; while (--t > 0);
diff --git a/extern/lzo/minilzo/minilzo.h b/extern/lzo/minilzo/minilzo.h
index 93916bc89b2..f2c104856e3 100644
--- a/extern/lzo/minilzo/minilzo.h
+++ b/extern/lzo/minilzo/minilzo.h
@@ -2,6 +2,9 @@
This file is part of the LZO real-time data compression library.
+ Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
@@ -45,9 +48,9 @@
#ifndef __MINILZO_H
-#define __MINILZO_H
+#define __MINILZO_H 1
-#define MINILZO_VERSION 0x2030
+#define MINILZO_VERSION 0x2060
#ifdef __LZOCONF_H
# error "you cannot use both LZO and miniLZO"
@@ -103,7 +106,6 @@ lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len,
#define LZO_HEAP_ALLOC(var,size) \
lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ]
-
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/intern/audaspace/FX/AUD_IDynamicIIRFilterCalculator.h b/intern/audaspace/FX/AUD_IDynamicIIRFilterCalculator.h
index 29b87e57ad0..2e0d8418571 100644
--- a/intern/audaspace/FX/AUD_IDynamicIIRFilterCalculator.h
+++ b/intern/audaspace/FX/AUD_IDynamicIIRFilterCalculator.h
@@ -40,6 +40,8 @@
class AUD_IDynamicIIRFilterCalculator
{
public:
+ virtual ~AUD_IDynamicIIRFilterCalculator() {}
+
/**
* Recalculates the filter coefficients.
* \param rate The sample rate of the audio data.
diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
index 831e1998182..47bfe4e69b9 100644
--- a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
+++ b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
@@ -133,6 +133,11 @@ void AUD_FFMPEGReader::init()
if(!aCodec)
AUD_THROW(AUD_ERROR_FFMPEG, nodecoder_error);
+#ifdef FFMPEG_SAMPLE_FMT_S16P_SUPPORTED
+ if(m_codecCtx->sample_fmt == AV_SAMPLE_FMT_S16P)
+ m_codecCtx->request_sample_fmt = AV_SAMPLE_FMT_S16;
+#endif
+
if(avcodec_open2(m_codecCtx, aCodec, NULL) < 0)
AUD_THROW(AUD_ERROR_FFMPEG, codecopen_error);
diff --git a/intern/audaspace/intern/AUD_Sequencer.h b/intern/audaspace/intern/AUD_Sequencer.h
index 9fdf537ff97..1066eeae8e3 100644
--- a/intern/audaspace/intern/AUD_Sequencer.h
+++ b/intern/audaspace/intern/AUD_Sequencer.h
@@ -100,7 +100,7 @@ public:
* \param muted Whether the whole scene is muted.
*/
AUD_Sequencer(AUD_Specs specs, float fps, bool muted);
- ~AUD_Sequencer();
+ virtual ~AUD_Sequencer();
/**
* Locks the sequence.
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 65f245fba69..09db010363e 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -416,6 +416,7 @@ class CyclesCameraSettings(bpy.types.PropertyGroup):
default=0.0,
step=1,
precision=4,
+ subtype = 'DISTANCE'
)
cls.aperture_blades = IntProperty(
name="Aperture Blades",
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 8da30acaf22..b928fb0984d 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -557,7 +557,7 @@ def panel_node_draw(layout, id_data, output_type, input_name):
node = find_node(id_data, output_type)
if not node:
- layout.label(text="No output node.")
+ layout.label(text="No output node")
else:
input = find_node_input(node, input_name)
layout.template_node_view(ntree, node, input)
@@ -620,7 +620,7 @@ class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel):
layout.prop(clamp, "use_multiple_importance_sampling")
if lamp.type == 'HEMI':
- layout.label(text="Not supported, interpreted as sun lamp.")
+ layout.label(text="Not supported, interpreted as sun lamp")
class CyclesLamp_PT_nodes(CyclesButtonsPanel, Panel):
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index a9d37dbed99..3472b067369 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -311,13 +311,48 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P
return object;
}
-static bool object_dupli_hide_original(BL::Object::dupli_type_enum dupli_type)
+static bool object_render_hide_original(BL::Object::dupli_type_enum dupli_type)
{
return (dupli_type == BL::Object::dupli_type_VERTS ||
dupli_type == BL::Object::dupli_type_FACES ||
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)
+{
+ /* check if we should render or hide particle emitter */
+ BL::Object::particle_systems_iterator b_psys;
+
+ bool hair_present = false;
+ bool show_emitter = false;
+ bool hide = false;
+
+ for(b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end(); ++b_psys) {
+ if((b_psys->settings().render_type() == BL::ParticleSettings::render_type_PATH) &&
+ (b_psys->settings().type()==BL::ParticleSettings::type_HAIR))
+ hair_present = true;
+
+ if(b_psys->settings().use_render_emitter()) {
+ hide = false;
+ show_emitter = true;
+ }
+ }
+
+ /* duplicators hidden by default, except dupliframes which duplicate self */
+ if(b_ob.is_duplicator())
+ if(top_level || b_ob.dupli_type() != BL::Object::dupli_type_FRAMES)
+ hide = true;
+
+ /* hide original object for duplis */
+ BL::Object parent = b_ob.parent();
+ if(parent && object_render_hide_original(parent.dupli_type()))
+ if(parent_hide)
+ hide = true;
+
+ hide_triangles = (hair_present && !show_emitter);
+ return hide;
+}
+
/* Object Loop */
void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
@@ -353,9 +388,6 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
progress.set_sync_status("Synchronizing object", (*b_ob).name());
if(b_ob->is_duplicator()) {
- /* duplicators hidden by default */
- hide = true;
-
/* dupli objects */
b_ob->dupli_list_create(b_scene, 2);
@@ -365,33 +397,16 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
Transform tfm = get_transform(b_dup->matrix());
BL::Object b_dup_ob = b_dup->object();
bool dup_hide = (b_v3d)? b_dup_ob.hide(): b_dup_ob.hide_render();
- bool emitter_hide = false;
-
- if(b_dup_ob.is_duplicator()) {
- /* duplicators hidden by default, except dupliframes which duplicate self */
- if(b_dup_ob.dupli_type() != BL::Object::dupli_type_FRAMES)
- emitter_hide = true;
-
- /* check if we should render or hide particle emitter */
- BL::Object::particle_systems_iterator b_psys;
- for(b_dup_ob.particle_systems.begin(b_psys); b_psys != b_dup_ob.particle_systems.end(); ++b_psys)
- if(b_psys->settings().use_render_emitter())
- emitter_hide = false;
- }
-
- /* hide original object for duplis */
- BL::Object parent = b_dup_ob.parent();
- if(parent && object_dupli_hide_original(parent.dupli_type()))
- if(b_dup->type() == BL::DupliObject::type_GROUP)
- dup_hide = true;
+ bool in_dupli_group = (b_dup->type() == BL::DupliObject::type_GROUP);
+ bool hide_tris;
- if(!(b_dup->hide() || dup_hide || emitter_hide)) {
+ if(!(b_dup->hide() || dup_hide || object_render_hide(b_dup_ob, false, in_dupli_group, hide_tris))) {
/* the persistent_id allows us to match dupli objects
* between frames and updates */
BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup->persistent_id();
/* sync object and mesh or light data */
- Object *object = sync_object(*b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion, false);
+ Object *object = sync_object(*b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion, hide_tris);
/* sync possible particle data, note particle_id
* starts counting at 1, first is dummy particle */
@@ -410,33 +425,10 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
b_ob->dupli_list_clear();
}
- /* check if we should render or hide particle emitter */
- BL::Object::particle_systems_iterator b_psys;
-
- bool hair_present = false;
- bool show_emitter = false;
- bool hide_tris = false;
-
- for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) {
-
- if((b_psys->settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys->settings().type()==BL::ParticleSettings::type_HAIR))
- hair_present = true;
-
- if(b_psys->settings().use_render_emitter()) {
- hide = false;
- show_emitter = true;
- }
- }
-
- if(hair_present && !show_emitter)
- hide_tris = true;
-
- /* hide original object for duplis */
- BL::Object parent = b_ob->parent();
- if(parent && object_dupli_hide_original(parent.dupli_type()))
- hide = true;
+ /* test if object needs to be hidden */
+ bool hide_tris;
- if(!hide) {
+ if(!object_render_hide(*b_ob, true, true, hide_tris)) {
/* object itself */
Transform tfm = get_transform(b_ob->matrix_world());
sync_object(*b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion, hide_tris);
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index b31650c160a..17008b7a7f3 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -301,6 +301,8 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc
device_free(device, dscene);
+ need_update = false;
+
if(scene->objects.size() == 0)
return;
@@ -322,8 +324,6 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc
/* allocate object flag */
device->tex_alloc("__object_flag", dscene->object_flag);
-
- need_update = false;
}
void ObjectManager::device_free(Device *device, DeviceScene *dscene)
diff --git a/intern/elbeem/intern/ntl_geometrymodel.cpp b/intern/elbeem/intern/ntl_geometrymodel.cpp
index 13220736b8e..62e4441bad7 100644
--- a/intern/elbeem/intern/ntl_geometrymodel.cpp
+++ b/intern/elbeem/intern/ntl_geometrymodel.cpp
@@ -215,7 +215,6 @@ void ntlGeometryObjModel::calcTriangleDivs(vector<ntlVec3Gfx> &verts, vector<ntl
errMsg("ntlGeometryObjModel","calcTriangleDivs special!");
mTriangleDivs1.resize( tris.size() );
mTriangleDivs2.resize( tris.size() );
- mTriangleDivs3.resize( tris.size() );
for(size_t i=0; i<tris.size(); i++) {
ntlVec3Gfx p0 = verts[ tris[i].getPoints()[0] ];
ntlVec3Gfx p1 = verts[ tris[i].getPoints()[1] ];
@@ -223,10 +222,9 @@ void ntlGeometryObjModel::calcTriangleDivs(vector<ntlVec3Gfx> &verts, vector<ntl
ntlVec3Gfx side1 = p1 - p0;
ntlVec3Gfx side2 = p2 - p0;
ntlVec3Gfx side3 = p1 - p2;
- int divs1=0, divs2=0, divs3=0;
+ int divs1=0, divs2=0;
if(normNoSqrt(side1) > fsTri*fsTri) { divs1 = (int)(norm(side1)/fsTri); }
if(normNoSqrt(side2) > fsTri*fsTri) { divs2 = (int)(norm(side2)/fsTri); }
- //if(normNoSqrt(side3) > fsTri*fsTri) { divs3 = (int)(norm(side3)/fsTri); }
// special handling
// warning, requires objmodel triangle treatment (no verts dups)
@@ -237,17 +235,15 @@ void ntlGeometryObjModel::calcTriangleDivs(vector<ntlVec3Gfx> &verts, vector<ntl
p1 = sverts[s].mVerts[ tris[i].getPoints()[1] ];
p2 = sverts[s].mVerts[ tris[i].getPoints()[2] ];
side1 = p1 - p0; side2 = p2 - p0; side3 = p1 - p2;
- int tdivs1=0, tdivs2=0, tdivs3=0;
+ int tdivs1=0, tdivs2=0;
if(normNoSqrt(side1) > fsTri*fsTri) { tdivs1 = (int)(norm(side1)/fsTri); }
if(normNoSqrt(side2) > fsTri*fsTri) { tdivs2 = (int)(norm(side2)/fsTri); }
if(tdivs1>divs1) divs1=tdivs1;
if(tdivs2>divs2) divs2=tdivs2;
- if(tdivs3>divs3) divs3=tdivs3;
}
} // */
mTriangleDivs1[i] = divs1;
mTriangleDivs2[i] = divs2;
- mTriangleDivs3[i] = divs3;
}
}
diff --git a/intern/elbeem/intern/ntl_geometryobject.cpp b/intern/elbeem/intern/ntl_geometryobject.cpp
index 1e08cb96a95..9b17b1854f2 100644
--- a/intern/elbeem/intern/ntl_geometryobject.cpp
+++ b/intern/elbeem/intern/ntl_geometryobject.cpp
@@ -42,7 +42,7 @@ ntlGeometryObject::ntlGeometryObject() :
mMovPoints(), mMovNormals(),
mHaveCachedMov(false),
mCachedMovPoints(), mCachedMovNormals(),
- mTriangleDivs1(), mTriangleDivs2(), mTriangleDivs3(),
+ mTriangleDivs1(), mTriangleDivs2(),
mMovPntsInited(-100.0), mMaxMovPnt(-1),
mcGeoActive(1.),
mCpsTimeStart(0.), mCpsTimeEnd(1.0), mCpsQuality(10.),
@@ -434,7 +434,6 @@ void ntlGeometryObject::applyTransformation(double t, vector<ntlVec3Gfx> *verts,
void ntlGeometryObject::calcTriangleDivs(vector<ntlVec3Gfx> &verts, vector<ntlTriangle> &tris, gfxReal fsTri) {
mTriangleDivs1.resize( tris.size() );
mTriangleDivs2.resize( tris.size() );
- mTriangleDivs3.resize( tris.size() );
//fsTri *= 2.; // DEBUG! , wrong init!
@@ -444,14 +443,12 @@ void ntlGeometryObject::calcTriangleDivs(vector<ntlVec3Gfx> &verts, vector<ntlTr
const ntlVec3Gfx p2 = verts[ tris[i].getPoints()[2] ];
const ntlVec3Gfx side1 = p1 - p0;
const ntlVec3Gfx side2 = p2 - p0;
- const ntlVec3Gfx side3 = p1 - p2;
- int divs1=0, divs2=0, divs3=0;
+ int divs1=0, divs2=0;
if(normNoSqrt(side1) > fsTri*fsTri) { divs1 = (int)(norm(side1)/fsTri); }
if(normNoSqrt(side2) > fsTri*fsTri) { divs2 = (int)(norm(side2)/fsTri); }
mTriangleDivs1[i] = divs1;
mTriangleDivs2[i] = divs2;
- mTriangleDivs3[i] = divs3;
}
}
diff --git a/intern/elbeem/intern/ntl_geometryobject.h b/intern/elbeem/intern/ntl_geometryobject.h
index fca539b8402..677f132f4c3 100644
--- a/intern/elbeem/intern/ntl_geometryobject.h
+++ b/intern/elbeem/intern/ntl_geometryobject.h
@@ -223,7 +223,7 @@ class ntlGeometryObject : public ntlGeometryClass
vector<ntlVec3Gfx> mCachedMovPoints;
vector<ntlVec3Gfx> mCachedMovNormals;
/*! precomputed triangle divisions */
- vector<int> mTriangleDivs1,mTriangleDivs2,mTriangleDivs3;
+ vector<int> mTriangleDivs1,mTriangleDivs2;
/*! inited? */
float mMovPntsInited;
/*! point with max. distance from center */
diff --git a/intern/elbeem/intern/ntl_ray.cpp b/intern/elbeem/intern/ntl_ray.cpp
index 7f5aedc53c6..1083fcdb68b 100644
--- a/intern/elbeem/intern/ntl_ray.cpp
+++ b/intern/elbeem/intern/ntl_ray.cpp
@@ -677,7 +677,6 @@ const ntlColor ntlRay::shade() //const
ntlScene::ntlScene( ntlRenderGlobals *glob, bool del ) :
mpGlob( glob ), mSceneDel(del),
mpTree( NULL ),
- mDisplayListId( -1 ),
mSceneBuilt( false ), mFirstInitDone( false )
{
}
diff --git a/intern/elbeem/intern/ntl_ray.h b/intern/elbeem/intern/ntl_ray.h
index 71fcd5f71c2..5f6d34e3020 100644
--- a/intern/elbeem/intern/ntl_ray.h
+++ b/intern/elbeem/intern/ntl_ray.h
@@ -404,9 +404,6 @@ private:
/*! Tree to store quickly intersect triangles */
ntlTree *mpTree;
- /*! id of dislpay list for raytracer stuff */
- int mDisplayListId;
-
/*! was the scene successfully built? only then getObject(i) requests are valid */
bool mSceneBuilt;
diff --git a/intern/elbeem/intern/solver_main.cpp b/intern/elbeem/intern/solver_main.cpp
index b9436e84922..99278657fd9 100644
--- a/intern/elbeem/intern/solver_main.cpp
+++ b/intern/elbeem/intern/solver_main.cpp
@@ -1170,7 +1170,6 @@ LbmFsgrSolver::standingFluidPreinit()
LbmFloat lcsmqo;
# if OPT3D==1
LbmFloat lcsmqadd, lcsmeq[LBM_DFNUM], lcsmomega;
- CellFlagType nbored=0;
# endif // OPT3D==true
GRID_LOOP_START();
diff --git a/intern/elbeem/intern/solver_util.cpp b/intern/elbeem/intern/solver_util.cpp
index 935a910e7d5..6eca427c787 100644
--- a/intern/elbeem/intern/solver_util.cpp
+++ b/intern/elbeem/intern/solver_util.cpp
@@ -731,15 +731,15 @@ void LbmFsgrSolver::advanceParticles() {
if(mPartUsePhysModel) {
LbmFloat radius = p->getSize() * minDropSize;
- LbmVec velPart = vec2L(p->getVel()) *cellsize/timestep; // L2RW, lattice velocity
- LbmVec velWater = LbmVec(vx,vy,vz) *cellsize/timestep;// L2RW, fluid velocity
- LbmVec velRel = velWater - velPart;
+ //LbmVec velPart = vec2L(p->getVel()) *cellsize/timestep; // L2RW, lattice velocity
+ //LbmVec velWater = LbmVec(vx,vy,vz) *cellsize/timestep;// L2RW, fluid velocity
+ //LbmVec velRel = velWater - velPart;
//LbmFloat velRelNorm = norm(velRel);
- LbmFloat pvolume = rhoAir * 4.0/3.0 * M_PI* radius*radius*radius; // volume: 4/3 pi r^3
+ //LbmFloat pvolume = rhoAir * 4.0/3.0 * M_PI* radius*radius*radius; // volume: 4/3 pi r^3
- LbmVec fb = -rwgrav* pvolume *rhoWater;
- LbmVec fd = velRel*6.0*M_PI*radius* (1e-3); //viscWater;
- LbmVec change = (fb+fd) *10.0*timestep *(timestep/cellsize);
+ //LbmVec fb = -rwgrav* pvolume *rhoWater;
+ //LbmVec fd = velRel*6.0*M_PI*radius* (1e-3); //viscWater;
+ //LbmVec change = (fb+fd) *10.0*timestep *(timestep/cellsize);
/*if(debugOutCounter<0) {
errMsg("PIT","BTEST1 vol="<<pvolume<<" radius="<<radius<<" vn="<<velRelNorm<<" velPart="<<velPart<<" velRel"<<velRel);
errMsg("PIT","BTEST2 cellsize="<<cellsize<<" timestep="<<timestep<<" viscW="<<viscWater<<" ss/mb="<<(timestep/(pvolume*rhoAir)));
diff --git a/intern/ffmpeg/ffmpeg_compat.h b/intern/ffmpeg/ffmpeg_compat.h
index c07dc869291..8663c96a22e 100644
--- a/intern/ffmpeg/ffmpeg_compat.h
+++ b/intern/ffmpeg/ffmpeg_compat.h
@@ -74,6 +74,7 @@
#if ((LIBAVUTIL_VERSION_MAJOR > 51) || (LIBAVUTIL_VERSION_MAJOR == 51) && (LIBAVUTIL_VERSION_MINOR >= 32))
#define FFMPEG_FFV1_ALPHA_SUPPORTED
+#define FFMPEG_SAMPLE_FMT_S16P_SUPPORTED
#endif
#if ((LIBAVUTIL_VERSION_MAJOR < 51) || (LIBAVUTIL_VERSION_MAJOR == 51) && (LIBAVUTIL_VERSION_MINOR < 22))
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 841293e09e4..37e82c29f80 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -249,12 +249,13 @@ public:
* \return The new window (or 0 if creation failed).
*/
virtual GHOST_IWindow *createWindow(
- const STR_String& title,
- GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height,
- GHOST_TWindowState state, GHOST_TDrawingContextType type,
- const bool stereoVisual = false,
- const GHOST_TUns16 numOfAASamples = 0,
- const GHOST_TEmbedderWindowID parentWindow = 0) = 0;
+ const STR_String& title,
+ GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height,
+ GHOST_TWindowState state, GHOST_TDrawingContextType type,
+ const bool stereoVisual = false,
+ const bool exclusive = false,
+ const GHOST_TUns16 numOfAASamples = 0,
+ const GHOST_TEmbedderWindowID parentWindow = 0) = 0;
/**
* Dispose a window.
@@ -277,8 +278,9 @@ public:
* This window is invalid after full screen has been ended.
* \return Indication of success.
*/
- virtual GHOST_TSuccess beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow **window,
- const bool stereoVisual, const GHOST_TUns16 numOfAASamples = 0) = 0;
+ virtual GHOST_TSuccess beginFullScreen(
+ const GHOST_DisplaySetting& setting, GHOST_IWindow **window,
+ const bool stereoVisual, const GHOST_TUns16 numOfAASamples = 0) = 0;
/**
* Updates the resolution while in fullscreen mode.
@@ -287,7 +289,8 @@ public:
*
* \return Indication of success.
*/
- virtual GHOST_TSuccess updateFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow **window) = 0;
+ virtual GHOST_TSuccess updateFullScreen(
+ const GHOST_DisplaySetting& setting, GHOST_IWindow **window) = 0;
/**
* Ends full screen mode.
diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h
index 4cf0dbfb820..a2d3e9b91fb 100644
--- a/intern/ghost/GHOST_IWindow.h
+++ b/intern/ghost/GHOST_IWindow.h
@@ -305,7 +305,10 @@ public:
*/
virtual GHOST_TSuccess setCursorGrab(GHOST_TGrabCursorMode mode, GHOST_Rect *bounds, GHOST_TInt32 mouse_ungrab_xy[2]) { return GHOST_kSuccess; }
-
+ /** */
+ virtual GHOST_TSuccess beginFullScreen() const = 0;
+ virtual GHOST_TSuccess endFullScreen() const = 0;
+
virtual float getNativePixelSize(void) = 0;
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 7622a2a7330..b73ff26c259 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -152,7 +152,8 @@ GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
bstereoVisual = false;
return (GHOST_WindowHandle) system->createWindow(title, left, top, width, height,
- state, type, bstereoVisual, numOfAASamples);
+ state, type, bstereoVisual, false,
+ numOfAASamples);
}
GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandle)
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index 080619bc0ac..5405fe7efe8 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -152,7 +152,7 @@ GHOST_TSuccess GHOST_System::beginFullScreen(const GHOST_DisplaySetting& setting
success = m_displayManager->setCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, setting);
if (success == GHOST_kSuccess) {
//GHOST_PRINT("GHOST_System::beginFullScreen(): creating full-screen window\n");
- success = createFullScreenWindow((GHOST_Window **)window, stereoVisual, numOfAASamples);
+ success = createFullScreenWindow((GHOST_Window **)window, setting, stereoVisual, numOfAASamples);
if (success == GHOST_kSuccess) {
m_windowManager->beginFullScreen(*window, stereoVisual);
}
@@ -347,26 +347,22 @@ GHOST_TSuccess GHOST_System::exit()
return GHOST_kSuccess;
}
-
-GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window, const bool stereoVisual, const GHOST_TUns16 numOfAASamples)
+GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window, const GHOST_DisplaySetting &settings,
+ const bool stereoVisual, const GHOST_TUns16 numOfAASamples)
{
- GHOST_TSuccess success;
+ /* note: don't use getCurrentDisplaySetting() because on X11 we may
+ * be zoomed in and the desktop may be bigger then the viewport. */
GHOST_ASSERT(m_displayManager, "GHOST_System::createFullScreenWindow(): invalid display manager");
- GHOST_DisplaySetting settings;
-
- success = m_displayManager->getCurrentDisplaySetting(GHOST_DisplayManager::kMainDisplay, settings);
- if (success) {
- //GHOST_PRINT("GHOST_System::createFullScreenWindow(): creating full-screen window\n");
- *window = (GHOST_Window *)createWindow(
- STR_String(""),
- 0, 0, settings.xPixels, settings.yPixels,
- GHOST_kWindowStateFullScreen,
- GHOST_kDrawingContextTypeOpenGL,
- stereoVisual,
- numOfAASamples);
- success = *window == 0 ? GHOST_kFailure : GHOST_kSuccess;
- }
- return success;
+ //GHOST_PRINT("GHOST_System::createFullScreenWindow(): creating full-screen window\n");
+ *window = (GHOST_Window *)createWindow(
+ STR_String(""),
+ 0, 0, settings.xPixels, settings.yPixels,
+ GHOST_kWindowStateNormal,
+ GHOST_kDrawingContextTypeOpenGL,
+ stereoVisual,
+ true, /* exclusive */
+ numOfAASamples);
+ return (*window == NULL) ? GHOST_kFailure : GHOST_kSuccess;
}
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index 928bbe6a31b..0d18dfe532f 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -330,7 +330,7 @@ protected:
* \param window The window created.
* \return Indication of success.
*/
- virtual GHOST_TSuccess createFullScreenWindow(GHOST_Window **window,
+ virtual GHOST_TSuccess createFullScreenWindow(GHOST_Window **window, const GHOST_DisplaySetting &settings,
const bool stereoVisual, const GHOST_TUns16 numOfAASamples = 0);
/** The display manager (platform dependant). */
diff --git a/intern/ghost/intern/GHOST_SystemCarbon.cpp b/intern/ghost/intern/GHOST_SystemCarbon.cpp
index bb6b1bfd4af..f7e035e890d 100644
--- a/intern/ghost/intern/GHOST_SystemCarbon.cpp
+++ b/intern/ghost/intern/GHOST_SystemCarbon.cpp
@@ -411,6 +411,7 @@ GHOST_IWindow *GHOST_SystemCarbon::createWindow(
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
bool stereoVisual,
+ const bool exclusive,
const GHOST_TUns16 numOfAASamples,
const GHOST_TEmbedderWindowID parentWindow)
{
diff --git a/intern/ghost/intern/GHOST_SystemCarbon.h b/intern/ghost/intern/GHOST_SystemCarbon.h
index b6821bc7419..9faf5423205 100644
--- a/intern/ghost/intern/GHOST_SystemCarbon.h
+++ b/intern/ghost/intern/GHOST_SystemCarbon.h
@@ -121,6 +121,7 @@ public:
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
const bool stereoVisual,
+ const bool exclusive = false,
const GHOST_TUns16 numOfAASamples = 0,
const GHOST_TEmbedderWindowID parentWindow = 0
);
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h
index 257aeb52a37..cbb61f6e6ea 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.h
+++ b/intern/ghost/intern/GHOST_SystemCocoa.h
@@ -119,6 +119,7 @@ public:
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
const bool stereoVisual = false,
+ const bool exclusive = false,
const GHOST_TUns16 numOfAASamples = 0,
const GHOST_TEmbedderWindowID parentWindow = 0
);
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index 6cf4ada6311..bc215ae4914 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -542,6 +542,7 @@ int cocoa_request_qtcodec_settings(bContext *C, wmOperator *op)
#pragma mark initialization/finalization
+const char *user_locale; // Global current user locale
GHOST_SystemCocoa::GHOST_SystemCocoa()
{
@@ -580,6 +581,12 @@ GHOST_SystemCocoa::GHOST_SystemCocoa()
rstring = NULL;
m_ignoreWindowSizedMessages = false;
+
+ //Get current locale
+ CFLocaleRef myCFLocale = CFLocaleCopyCurrent();
+ NSLocale *myNSLocale = (NSLocale *)CFBridgingRelease(myCFLocale);
+ NSString *nsIdentifier = [myNSLocale localeIdentifier];
+ user_locale = [nsIdentifier UTF8String];
}
GHOST_SystemCocoa::~GHOST_SystemCocoa()
@@ -734,6 +741,7 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow(
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
bool stereoVisual,
+ const bool exclusive,
const GHOST_TUns16 numOfAASamples,
const GHOST_TEmbedderWindowID parentWindow
)
@@ -1772,7 +1780,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
//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);
}
else {
- pushEvent( new GHOST_EventKey([event timestamp] * 1000, GHOST_kEventKeyUp, window, keyCode, 0, '\0') );
+ 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);
}
break;
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 3005930d30c..a6e14ac362e 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -217,15 +217,15 @@ void GHOST_SystemWin32::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns
void GHOST_SystemWin32::getAllDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const
{
- width = ::GetSystemMetrics(SM_XVIRTUALSCREEN);
- height = ::GetSystemMetrics(SM_YVIRTUALSCREEN);
+ width = ::GetSystemMetrics(SM_CXVIRTUALSCREEN);
+ height = ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
}
GHOST_IWindow *GHOST_SystemWin32::createWindow(
const STR_String& title,
GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height,
GHOST_TWindowState state, GHOST_TDrawingContextType type,
- bool stereoVisual, const GHOST_TUns16 numOfAASamples, const GHOST_TEmbedderWindowID parentWindow)
+ bool stereoVisual, const bool exclusive, const GHOST_TUns16 numOfAASamples, const GHOST_TEmbedderWindowID parentWindow)
{
GHOST_Window *window = 0;
window = new GHOST_WindowWin32(this, title, left, top, width, height, state, type, stereoVisual, numOfAASamples, parentWindow);
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index e47dbda2e92..c4b81677c18 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -128,6 +128,7 @@ public:
GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height,
GHOST_TWindowState state, GHOST_TDrawingContextType type,
const bool stereoVisual = false,
+ const bool exclusive = false,
const GHOST_TUns16 numOfAASamples = 0,
const GHOST_TEmbedderWindowID parentWindow = 0);
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 48fb8375303..d00265fbd9b 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -278,6 +278,8 @@ getAllDisplayDimensions(
* \param state The state of the window when opened.
* \param type The type of drawing context installed in this window.
* \param stereoVisual Stereo visual for quad buffered stereo.
+ * \param exclusive Use to show the window ontop and ignore others
+ * (used fullscreen).
* \param numOfAASamples Number of samples used for AA (zero if no AA)
* \param parentWindow Parent (embedder) window
* \return The new window (or 0 if creation failed).
@@ -292,7 +294,8 @@ createWindow(
GHOST_TUns32 height,
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
- bool stereoVisual,
+ const bool stereoVisual,
+ const bool exclusive,
const GHOST_TUns16 numOfAASamples,
const GHOST_TEmbedderWindowID parentWindow)
{
@@ -305,7 +308,9 @@ createWindow(
window = new GHOST_WindowX11(this, m_display, title,
left, top, width, height,
- state, parentWindow, type, stereoVisual, numOfAASamples);
+ state, parentWindow, type,
+ stereoVisual, exclusive,
+ numOfAASamples);
if (window) {
/* Both are now handle in GHOST_WindowX11.cpp
diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h
index a11aea240be..6a492f64b41 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -137,7 +137,9 @@ public:
* \param height The height the window.
* \param state The state of the window when opened.
* \param type The type of drawing context installed in this window.
- * \param stereoVisual Create a stereo visual for quad buffered stereo.
+ * \param stereoVisual Create a stereo visual for quad buffered stereo.
+ * \param exclusive Use to show the window ontop and ignore others
+ * (used fullscreen).
* \param parentWindow Parent (embedder) window
* \return The new window (or 0 if creation failed).
*/
@@ -151,6 +153,7 @@ public:
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
const bool stereoVisual,
+ const bool exclusive = false,
const GHOST_TUns16 numOfAASamples = 0,
const GHOST_TEmbedderWindowID parentWindow = 0
);
diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp
index ca12abe7324..6c2d7350cd9 100644
--- a/intern/ghost/intern/GHOST_Window.cpp
+++ b/intern/ghost/intern/GHOST_Window.cpp
@@ -45,6 +45,7 @@ GHOST_Window::GHOST_Window(
GHOST_TWindowState state,
GHOST_TDrawingContextType type,
const bool stereoVisual,
+ const bool exclusive,
const GHOST_TUns16 numOfAASamples)
:
m_drawingContextType(type),
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index f7c67bf7be6..588de0911e3 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -80,6 +80,8 @@ public:
* \param state The state the window is initially opened with.
* \param type The type of drawing context installed in this window.
* \param stereoVisual Stereo visual for quad buffered stereo.
+ * \param exclusive Use to show the window ontop and ignore others
+ * (used fullscreen).
* \param numOfAASamples Number of samples used for AA (zero if no AA)
*/
GHOST_Window(
@@ -88,6 +90,7 @@ public:
GHOST_TWindowState state,
GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone,
const bool stereoVisual = false,
+ const bool exclusive = false,
const GHOST_TUns16 numOfAASamples = 0);
/**
diff --git a/intern/ghost/intern/GHOST_WindowCarbon.h b/intern/ghost/intern/GHOST_WindowCarbon.h
index d25d57156f6..16f305e93c5 100644
--- a/intern/ghost/intern/GHOST_WindowCarbon.h
+++ b/intern/ghost/intern/GHOST_WindowCarbon.h
@@ -220,6 +220,11 @@ public:
{
return m_tablet;
}
+
+ GHOST_TSuccess beginFullScreen() const {return GHOST_kFailure;}
+
+ GHOST_TSuccess endFullScreen() const {return GHOST_kFailure;}
+
protected:
/**
* Tries to install a rendering context in this window.
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h
index f1388c0b466..fe0830edeae 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.h
+++ b/intern/ghost/intern/GHOST_WindowCocoa.h
@@ -266,6 +266,10 @@ public:
virtual void setNativePixelSize(void);
+ GHOST_TSuccess beginFullScreen() const {return GHOST_kFailure;}
+
+ GHOST_TSuccess endFullScreen() const {return GHOST_kFailure;}
+
protected:
/**
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index 8d5f8bf89d5..6517e3fb9f9 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -514,6 +514,8 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize;
pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32;
+ pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccumSize;
+ pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32;
if (stereoVisual) pixelFormatAttrsWindow[i++] = NSOpenGLPFAStereo;
@@ -556,6 +558,9 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize;
pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32;
+
+ pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccumSize;
+ pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32;
if (stereoVisual) pixelFormatAttrsWindow[i++] = NSOpenGLPFAStereo;
diff --git a/intern/ghost/intern/GHOST_WindowManager.cpp b/intern/ghost/intern/GHOST_WindowManager.cpp
index daf1c2f2d22..1f20e01ca73 100644
--- a/intern/ghost/intern/GHOST_WindowManager.cpp
+++ b/intern/ghost/intern/GHOST_WindowManager.cpp
@@ -130,12 +130,12 @@ GHOST_TSuccess GHOST_WindowManager::beginFullScreen(GHOST_IWindow *window,
m_fullScreenWindow = window;
m_activeWindowBeforeFullScreen = getActiveWindow();
setActiveWindow(m_fullScreenWindow);
+ m_fullScreenWindow->beginFullScreen();
success = GHOST_kSuccess;
}
return success;
}
-
GHOST_TSuccess GHOST_WindowManager::endFullScreen(void)
{
GHOST_TSuccess success = GHOST_kFailure;
@@ -143,6 +143,7 @@ GHOST_TSuccess GHOST_WindowManager::endFullScreen(void)
if (m_fullScreenWindow != 0) {
//GHOST_PRINT("GHOST_WindowManager::endFullScreen(): deleting full-screen window\n");
setWindowInactive(m_fullScreenWindow);
+ m_fullScreenWindow->endFullScreen();
delete m_fullScreenWindow;
//GHOST_PRINT("GHOST_WindowManager::endFullScreen(): done\n");
m_fullScreenWindow = 0;
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 7566e7fe71c..b1a9ca52605 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -104,13 +104,14 @@ static PIXELFORMATDESCRIPTOR sPreferredFormat = {
* can't be in multiple-devices configuration. */
static int is_crappy_intel_card(void)
{
- int crappy = 0;
- const char *vendor = (const char *)glGetString(GL_VENDOR);
+ static short is_crappy = -1;
- if (strstr(vendor, "Intel"))
- crappy = 1;
+ if (is_crappy == -1) {
+ const char *vendor = (const char *)glGetString(GL_VENDOR);
+ is_crappy = (strstr(vendor, "Intel") != NULL);
+ }
- return crappy;
+ return is_crappy;
}
GHOST_WindowWin32::GHOST_WindowWin32(
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index 7f50d58ce35..2af4b703930 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -276,6 +276,10 @@ public:
void processWin32TabletEvent(WPARAM wParam, LPARAM lParam);
void bringTabletContextToFront();
+ GHOST_TSuccess beginFullScreen() const {return GHOST_kFailure;}
+
+ GHOST_TSuccess endFullScreen() const {return GHOST_kFailure;}
+
protected:
GHOST_TSuccess initMultisample(PIXELFORMATDESCRIPTOR pfd);
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index 8184475b610..05ab24492c2 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -165,9 +165,10 @@ GHOST_WindowX11(
const GHOST_TEmbedderWindowID parentWindow,
GHOST_TDrawingContextType type,
const bool stereoVisual,
+ const bool exclusive,
const GHOST_TUns16 numOfAASamples
) :
- GHOST_Window(width, height, state, type, stereoVisual, numOfAASamples),
+ GHOST_Window(width, height, state, type, stereoVisual, exclusive, numOfAASamples),
m_context(NULL),
m_display(display),
m_normal_state(GHOST_kWindowStateNormal),
@@ -254,6 +255,7 @@ GHOST_WindowX11(
* This seems pretty much a legacy feature as we are in rgba mode anyway. */
XSetWindowAttributes xattributes;
+ unsigned int xattributes_valuemask = (CWBorderPixel | CWColormap | CWEventMask);
memset(&xattributes, 0, sizeof(xattributes));
xattributes.colormap = XCreateColormap(m_display,
@@ -274,6 +276,11 @@ GHOST_WindowX11(
PointerMotionMask | FocusChangeMask |
PropertyChangeMask | KeymapStateMask;
+ if (exclusive) {
+ xattributes_valuemask |= CWOverrideRedirect;
+ xattributes.override_redirect = True;
+ }
+
/* create the window! */
if (parentWindow == 0) {
m_window = XCreateWindow(m_display,
@@ -286,7 +293,7 @@ GHOST_WindowX11(
m_visual->depth,
InputOutput,
m_visual->visual,
- CWBorderPixel | CWColormap | CWEventMask,
+ xattributes_valuemask,
&xattributes
);
}
@@ -315,7 +322,7 @@ GHOST_WindowX11(
m_visual->depth,
InputOutput,
m_visual->visual,
- CWBorderPixel | CWColormap | CWEventMask,
+ xattributes_valuemask,
&xattributes
);
@@ -486,7 +493,12 @@ GHOST_WindowX11(
GHOST_PRINT("Created window\n");
}
- XMapWindow(m_display, m_window);
+ if (exclusive) {
+ XMapRaised(m_display, m_window);
+ }
+ else {
+ XMapWindow(m_display, m_window);
+ }
GHOST_PRINT("Mapped window\n");
XFlush(m_display);
@@ -1498,3 +1510,44 @@ setWindowCustomCursorShape(
return GHOST_kSuccess;
}
+
+
+GHOST_TSuccess
+GHOST_WindowX11::
+beginFullScreen() const
+{
+ {
+ Window root_return;
+ int x_return, y_return;
+ unsigned int w_return, h_return, border_w_return, depth_return;
+
+ XGetGeometry(m_display, m_window, &root_return, &x_return, &y_return,
+ &w_return, &h_return, &border_w_return, &depth_return);
+
+ m_system->setCursorPosition(w_return / 2, h_return / 2);
+ }
+
+
+ /* Grab Keyboard & Mouse */
+ int err;
+
+ err = XGrabKeyboard(m_display, m_window, False,
+ GrabModeAsync, GrabModeAsync, CurrentTime);
+ if (err != GrabSuccess) printf("XGrabKeyboard failed %d\n", err);
+
+ err = XGrabPointer(m_display, m_window, False, PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime);
+ if (err != GrabSuccess) printf("XGrabPointer failed %d\n", err);
+
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess
+GHOST_WindowX11::
+endFullScreen() const
+{
+ XUngrabKeyboard(m_display, CurrentTime);
+ XUngrabPointer(m_display, CurrentTime);
+
+ return GHOST_kSuccess;
+}
diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h
index 10d44987647..b8471b41a11 100644
--- a/intern/ghost/intern/GHOST_WindowX11.h
+++ b/intern/ghost/intern/GHOST_WindowX11.h
@@ -87,6 +87,7 @@ public:
const GHOST_TEmbedderWindowID parentWindow,
GHOST_TDrawingContextType type = GHOST_kDrawingContextTypeNone,
const bool stereoVisual = false,
+ const bool exclusive = false,
const GHOST_TUns16 numOfAASamples = 0
);
@@ -230,6 +231,10 @@ public:
bool m_post_init;
GHOST_TWindowState m_post_state;
+ GHOST_TSuccess beginFullScreen() const;
+
+ GHOST_TSuccess endFullScreen() const;
+
protected:
/**
* Tries to install a rendering context in this window.
diff --git a/intern/iksolver/intern/IK_Solver.cpp b/intern/iksolver/intern/IK_Solver.cpp
index c1a4ffcb1e8..65ea4d64ab1 100644
--- a/intern/iksolver/intern/IK_Solver.cpp
+++ b/intern/iksolver/intern/IK_Solver.cpp
@@ -348,6 +348,7 @@ float IK_SolverGetPoleAngle(IK_Solver *solver)
return qsolver->solver.GetPoleAngle();
}
+#if 0
static void IK_SolverAddCenterOfMass(IK_Solver *solver, IK_Segment *root, float goal[3], float weight)
{
if (solver == NULL || root == NULL)
@@ -363,6 +364,7 @@ static void IK_SolverAddCenterOfMass(IK_Solver *solver, IK_Segment *root, float
com->SetWeight(weight);
qsolver->tasks.push_back(com);
}
+#endif
int IK_Solve(IK_Solver *solver, float tolerance, int max_iterations)
{
diff --git a/intern/itasc/Armature.cpp b/intern/itasc/Armature.cpp
index 78780ed8ba3..19f37a79484 100644
--- a/intern/itasc/Armature.cpp
+++ b/intern/itasc/Armature.cpp
@@ -32,7 +32,9 @@ Armature::Armature():
m_qCCh(-1),
m_qCTs(0),
m_yCCh(-1),
+#if 0
m_yCTs(0),
+#endif
m_qKdl(),
m_oldqKdl(),
m_newqKdl(),
diff --git a/intern/itasc/Armature.hpp b/intern/itasc/Armature.hpp
index 63d1899f4e9..3167247ab03 100644
--- a/intern/itasc/Armature.hpp
+++ b/intern/itasc/Armature.hpp
@@ -111,7 +111,9 @@ private:
int m_qCCh;
CacheTS m_qCTs;
int m_yCCh;
+#if 0
CacheTS m_yCTs;
+#endif
JntArray m_qKdl;
JntArray m_oldqKdl;
JntArray m_newqKdl;
diff --git a/intern/itasc/kdl/segment.cpp b/intern/itasc/kdl/segment.cpp
index f963559c4c8..fbb775f6682 100644
--- a/intern/itasc/kdl/segment.cpp
+++ b/intern/itasc/kdl/segment.cpp
@@ -25,13 +25,13 @@
namespace KDL {
Segment::Segment(const Joint& _joint, const Frame& _f_tip, const Inertia& _M):
- joint(_joint),M(_M),
+ M(_M),joint(_joint),
f_tip(_f_tip)
{
}
Segment::Segment(const Segment& in):
- joint(in.joint),M(in.M),
+ M(in.M),joint(in.joint),
f_tip(in.f_tip)
{
}
diff --git a/intern/locale/boost_locale_wrapper.cpp b/intern/locale/boost_locale_wrapper.cpp
index ebd2dd652c7..ef22e31e3cf 100644
--- a/intern/locale/boost_locale_wrapper.cpp
+++ b/intern/locale/boost_locale_wrapper.cpp
@@ -66,28 +66,7 @@ void bl_locale_set(const char *locale)
}
else {
#ifdef __APPLE__
- // workaround to get osx system locale from user defaults
- FILE *fp;
- std::string locale_osx = "";
- char result[16];
- int result_len = 0;
-
- fp = popen("defaults read .GlobalPreferences AppleLocale", "r");
-
- if (fp) {
- result_len = fread(result, 1, sizeof(result) - 1, fp);
-
- if (result_len > 0) {
- result[result_len - 1] = '\0'; // \0 terminate and remove \n
- locale_osx = std::string(result) + std::string(".UTF-8");
- }
-
- pclose(fp);
- }
-
- if (locale_osx == "")
- fprintf(stderr, "Locale set: failed to read AppleLocale read from defaults\n");
-
+ std::string locale_osx = user_locale + std::string(".UTF-8");
_locale = gen(locale_osx.c_str());
std::locale::global(_locale);
#else
diff --git a/intern/locale/boost_locale_wrapper.h b/intern/locale/boost_locale_wrapper.h
index 4e3a1f848d2..22f3793ae67 100644
--- a/intern/locale/boost_locale_wrapper.h
+++ b/intern/locale/boost_locale_wrapper.h
@@ -42,7 +42,11 @@ void bl_locale_init(const char *messages_path, const char *default_domain);
void bl_locale_set(const char *locale);
const char *bl_locale_get(void);
const char *bl_locale_pgettext(const char *msgctxt, const char *msgid);
-
+
+#ifdef __APPLE__
+extern const char *user_locale; // pulled from Ghost_SystemCocoa
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/intern/smoke/intern/FLUID_3D.h b/intern/smoke/intern/FLUID_3D.h
index 8cadf3bc989..d98a39930de 100644
--- a/intern/smoke/intern/FLUID_3D.h
+++ b/intern/smoke/intern/FLUID_3D.h
@@ -41,9 +41,9 @@
using namespace std;
using namespace BasicVector;
-class WTURBULENCE;
+struct WTURBULENCE;
-class FLUID_3D
+struct FLUID_3D
{
public:
FLUID_3D(int *res, float dx, float dtdef, int init_heat, int init_fire, int init_colors);
diff --git a/intern/smoke/intern/FLUID_3D_STATIC.cpp b/intern/smoke/intern/FLUID_3D_STATIC.cpp
index ac485ad983a..e0a31a9d0c1 100644
--- a/intern/smoke/intern/FLUID_3D_STATIC.cpp
+++ b/intern/smoke/intern/FLUID_3D_STATIC.cpp
@@ -200,13 +200,15 @@ void FLUID_3D::setZeroZ(float* field, Vec3Int res, int zBegin, int zEnd)
const int totalCells = res[0] * res[1] * res[2];
int index = 0;
- if ((zBegin == 0))
- for (int y = 0; y < res[1]; y++)
- for (int x = 0; x < res[0]; x++, index++)
- {
- // front slab
- field[index] = 0.0f;
- }
+ if (zBegin == 0)
+ {
+ for (int y = 0; y < res[1]; y++)
+ for (int x = 0; x < res[0]; x++, index++)
+ {
+ // front slab
+ field[index] = 0.0f;
+ }
+ }
if (zEnd == res[2])
{
@@ -265,27 +267,29 @@ void FLUID_3D::copyBorderZ(float* field, Vec3Int res, int zBegin, int zEnd)
const int totalCells = res[0] * res[1] * res[2];
int index=0;
- if ((zBegin == 0))
- for (int y = 0; y < res[1]; y++)
- for (int x = 0; x < res[0]; x++, index++)
- {
- field[index] = field[index + slabSize];
- }
+ if (zBegin == 0)
+ {
+ for (int y = 0; y < res[1]; y++)
+ for (int x = 0; x < res[0]; x++, index++)
+ {
+ field[index] = field[index + slabSize];
+ }
+ }
- if ((zEnd == res[2]))
+ if (zEnd == res[2])
{
- index=0;
- int indexx=0;
- const int cellsslab = totalCells - slabSize;
+ index=0;
+ int indexx=0;
+ const int cellsslab = totalCells - slabSize;
- for (int y = 0; y < res[1]; y++)
- for (int x = 0; x < res[0]; x++, index++)
- {
- // back slab
- indexx = index + cellsslab;
- field[indexx] = field[indexx - slabSize];
- }
+ for (int y = 0; y < res[1]; y++)
+ for (int x = 0; x < res[0]; x++, index++)
+ {
+ // back slab
+ indexx = index + cellsslab;
+ field[indexx] = field[indexx - slabSize];
+ }
}
}
diff --git a/intern/smoke/intern/WTURBULENCE.h b/intern/smoke/intern/WTURBULENCE.h
index 1655bd95d32..4e76466bde5 100644
--- a/intern/smoke/intern/WTURBULENCE.h
+++ b/intern/smoke/intern/WTURBULENCE.h
@@ -32,7 +32,7 @@ class SIMPLE_PARSER;
///////////////////////////////////////////////////////////////////////////////
/// Main WTURBULENCE class, stores large density array etc.
///////////////////////////////////////////////////////////////////////////////
-class WTURBULENCE
+struct WTURBULENCE
{
public:
// both config files can be NULL, altCfg might override values from noiseCfg
diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
new file mode 100644
index 00000000000..21c0a943984
--- /dev/null
+++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
@@ -0,0 +1,908 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public 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>
+
+# Populate a template file (POT format currently) from Blender RNA/py/C data.
+# XXX: This script is meant to be used from inside Blender!
+# You should not directly use this script, rather use update_msg.py!
+
+import collections
+import copy
+import datetime
+import os
+import re
+import sys
+
+# XXX Relative import does not work here when used from Blender...
+from bl_i18n_utils import settings as i18n_settings, utils
+
+import bpy
+
+##### Utils #####
+
+# check for strings like "+%f°"
+ignore_reg = re.compile(r"^(?:[-*.()/\\+%°0-9]|%d|%f|%s|%r|\s)*$")
+filter_message = ignore_reg.match
+
+
+def init_spell_check(settings, lang="en_US"):
+ try:
+ from bl_i18n_utils import spell_check_utils
+ return spell_check_utils.SpellChecker(settings, lang)
+ except Exception as e:
+ print("Failed to import spell_check_utils ({})".format(str(e)))
+ return None
+
+
+def _gen_check_ctxt(settings):
+ return {
+ "multi_rnatip": set(),
+ "multi_lines": set(),
+ "py_in_rna": set(),
+ "not_capitalized": set(),
+ "end_point": set(),
+ "undoc_ops": set(),
+ "spell_checker": init_spell_check(settings),
+ "spell_errors": {},
+ }
+
+
+def _gen_reports(check_ctxt):
+ return {
+ "check_ctxt": check_ctxt,
+ "rna_structs": [],
+ "rna_structs_skipped": [],
+ "rna_props": [],
+ "rna_props_skipped": [],
+ "py_messages": [],
+ "py_messages_skipped": [],
+ "src_messages": [],
+ "src_messages_skipped": [],
+ "messages_skipped": set(),
+ }
+
+
+def check(check_ctxt, msgs, key, msgsrc, settings):
+ """
+ Performs a set of checks over the given key (context, message)...
+ """
+ if check_ctxt is None:
+ return
+ multi_rnatip = check_ctxt.get("multi_rnatip")
+ multi_lines = check_ctxt.get("multi_lines")
+ py_in_rna = check_ctxt.get("py_in_rna")
+ not_capitalized = check_ctxt.get("not_capitalized")
+ end_point = check_ctxt.get("end_point")
+ undoc_ops = check_ctxt.get("undoc_ops")
+ spell_checker = check_ctxt.get("spell_checker")
+ spell_errors = check_ctxt.get("spell_errors")
+
+ if multi_rnatip is not None:
+ if key in msgs and key not in multi_rnatip:
+ multi_rnatip.add(key)
+ if multi_lines is not None:
+ if '\n' in key[1]:
+ multi_lines.add(key)
+ if py_in_rna is not None:
+ if key in py_in_rna[1]:
+ py_in_rna[0].add(key)
+ if not_capitalized is not None:
+ if(key[1] not in settings.WARN_MSGID_NOT_CAPITALIZED_ALLOWED and
+ key[1][0].isalpha() and not key[1][0].isupper()):
+ not_capitalized.add(key)
+ if end_point is not None:
+ if (key[1].strip().endswith('.') and not key[1].strip().endswith('...') and
+ key[1] not in settings.WARN_MSGID_END_POINT_ALLOWED):
+ end_point.add(key)
+ if undoc_ops is not None:
+ if key[1] == settings.UNDOC_OPS_STR:
+ undoc_ops.add(key)
+ if spell_checker is not None and spell_errors is not None:
+ err = spell_checker.check(key[1])
+ if err:
+ spell_errors[key] = err
+
+
+def print_info(reports, pot):
+ def _print(*args, **kwargs):
+ kwargs["file"] = sys.stderr
+ print(*args, **kwargs)
+
+ pot.update_info()
+
+ _print("{} RNA structs were processed (among which {} were skipped), containing {} RNA properties "
+ "(among which {} were skipped).".format(len(reports["rna_structs"]), len(reports["rna_structs_skipped"]),
+ len(reports["rna_props"]), len(reports["rna_props_skipped"])))
+ _print("{} messages were extracted from Python UI code (among which {} were skipped), and {} from C source code "
+ "(among which {} were skipped).".format(len(reports["py_messages"]), len(reports["py_messages_skipped"]),
+ len(reports["src_messages"]), len(reports["src_messages_skipped"])))
+ _print("{} messages were rejected.".format(len(reports["messages_skipped"])))
+ _print("\n")
+ _print("Current POT stats:")
+ pot.print_stats(prefix="\t", output=_print)
+ _print("\n")
+
+ check_ctxt = reports["check_ctxt"]
+ if check_ctxt is None:
+ return
+ multi_rnatip = check_ctxt.get("multi_rnatip")
+ multi_lines = check_ctxt.get("multi_lines")
+ py_in_rna = check_ctxt.get("py_in_rna")
+ not_capitalized = check_ctxt.get("not_capitalized")
+ end_point = check_ctxt.get("end_point")
+ undoc_ops = check_ctxt.get("undoc_ops")
+ spell_errors = check_ctxt.get("spell_errors")
+
+ # XXX Temp, no multi_rnatip nor py_in_rna, see below.
+ keys = multi_lines | not_capitalized | end_point | undoc_ops | spell_errors.keys()
+ if keys:
+ _print("WARNINGS:")
+ for key in keys:
+ if undoc_ops and key in undoc_ops:
+ _print("\tThe following operators are undocumented!")
+ else:
+ _print("\t“{}”|“{}”:".format(*key))
+ if multi_lines and key in multi_lines:
+ _print("\t\t-> newline in this message!")
+ if not_capitalized and key in not_capitalized:
+ _print("\t\t-> message not capitalized!")
+ if end_point and key in end_point:
+ _print("\t\t-> message with endpoint!")
+ # XXX Hide this one for now, too much false positives.
+# if multi_rnatip and key in multi_rnatip:
+# _print("\t\t-> tip used in several RNA items")
+# if py_in_rna and key in py_in_rna:
+# _print("\t\t-> RNA message also used in py UI code!")
+ if spell_errors and spell_errors.get(key):
+ lines = ["\t\t-> {}: misspelled, suggestions are ({})".format(w, "'" + "', '".join(errs) + "'")
+ for w, errs in spell_errors[key]]
+ _print("\n".join(lines))
+ _print("\t\t{}".format("\n\t\t".join(pot.msgs[key].sources)))
+
+
+def enable_addons(addons={}, support={}, disable=False):
+ """
+ Enable (or disable) addons based either on a set of names, or a set of 'support' types.
+ Returns the list of all affected addons (as fake modules)!
+ """
+ import addon_utils
+
+ userpref = bpy.context.user_preferences
+ used_ext = {ext.module for ext in userpref.addons}
+
+ ret = [mod for mod in addon_utils.modules(addon_utils.addons_fake_modules)
+ if ((addons and mod.__name__ in addons) or
+ (not addons and addon_utils.module_bl_info(mod)["support"] in support))]
+
+ for mod in ret:
+ module_name = mod.__name__
+ if disable:
+ if module_name not in used_ext:
+ continue
+ print(" Disabling module ", module_name)
+ bpy.ops.wm.addon_disable(module=module_name)
+ else:
+ if module_name in used_ext:
+ continue
+ print(" Enabling module ", module_name)
+ bpy.ops.wm.addon_enable(module=module_name)
+
+ # XXX There are currently some problems with bpy/rna...
+ # *Very* tricky to solve!
+ # So this is a hack to make all newly added operator visible by
+ # bpy.types.OperatorProperties.__subclasses__()
+ for cat in dir(bpy.ops):
+ cat = getattr(bpy.ops, cat)
+ for op in dir(cat):
+ getattr(cat, op).get_rna()
+
+ return ret
+
+
+def process_msg(msgs, msgctxt, msgid, msgsrc, reports, check_ctxt, settings):
+ if filter_message(msgid):
+ reports["messages_skipped"].add((msgid, msgsrc))
+ return
+ if not msgctxt:
+ # We do *not* want any "" context!
+ msgctxt = settings.DEFAULT_CONTEXT
+ # Always unescape keys!
+ msgctxt = utils.I18nMessage.do_unescape(msgctxt)
+ msgid = utils.I18nMessage.do_unescape(msgid)
+ key = (msgctxt, msgid)
+ check(check_ctxt, msgs, key, msgsrc, settings)
+ msgsrc = settings.PO_COMMENT_PREFIX_SOURCE_CUSTOM + msgsrc
+ if key not in msgs:
+ msgs[key] = utils.I18nMessage([msgctxt], [msgid], [], [msgsrc], settings=settings)
+ else:
+ msgs[key].comment_lines.append(msgsrc)
+
+
+##### RNA #####
+def dump_messages_rna(msgs, reports, settings):
+ """
+ Dump into messages dict all RNA-defined UI messages (labels en tooltips).
+ """
+ def class_blacklist():
+ blacklist_rna_class = [
+ # core classes
+ "Context", "Event", "Function", "UILayout", "BlendData", "UnknownType",
+ # registerable classes
+ "Panel", "Menu", "Header", "RenderEngine", "Operator", "OperatorMacro", "Macro", "KeyingSetInfo",
+ # window classes
+ "Window",
+ ]
+
+ # Collect internal operators
+ # extend with all internal operators
+ # note that this uses internal api introspection functions
+ # all possible operator names
+ op_ids = set(cls.bl_rna.identifier for cls in bpy.types.OperatorProperties.__subclasses__()) | \
+ set(cls.bl_rna.identifier for cls in bpy.types.Operator.__subclasses__()) | \
+ set(cls.bl_rna.identifier for cls in bpy.types.OperatorMacro.__subclasses__())
+
+ get_instance = __import__("_bpy").ops.get_instance
+# path_resolve = type(bpy.context).__base__.path_resolve
+ for idname in op_ids:
+ op = get_instance(idname)
+ # XXX Do not skip INTERNAL's anymore, some of those ops show up in UI now!
+# if 'INTERNAL' in path_resolve(op, "bl_options"):
+# blacklist_rna_class.append(idname)
+
+ # Collect builtin classes we don't need to doc
+ blacklist_rna_class.append("Property")
+ blacklist_rna_class.extend([cls.__name__ for cls in bpy.types.Property.__subclasses__()])
+
+ # Collect classes which are attached to collections, these are api access only.
+ collection_props = set()
+ for cls_id in dir(bpy.types):
+ cls = getattr(bpy.types, cls_id)
+ for prop in cls.bl_rna.properties:
+ if prop.type == 'COLLECTION':
+ prop_cls = prop.srna
+ if prop_cls is not None:
+ collection_props.add(prop_cls.identifier)
+ blacklist_rna_class.extend(sorted(collection_props))
+
+ return blacklist_rna_class
+
+ check_ctxt_rna = check_ctxt_rna_tip = None
+ check_ctxt = reports["check_ctxt"]
+ if check_ctxt:
+ check_ctxt_rna = {
+ "multi_lines": check_ctxt.get("multi_lines"),
+ "not_capitalized": check_ctxt.get("not_capitalized"),
+ "end_point": check_ctxt.get("end_point"),
+ "undoc_ops": check_ctxt.get("undoc_ops"),
+ "spell_checker": check_ctxt.get("spell_checker"),
+ "spell_errors": check_ctxt.get("spell_errors"),
+ }
+ check_ctxt_rna_tip = check_ctxt_rna
+ check_ctxt_rna_tip["multi_rnatip"] = check_ctxt.get("multi_rnatip")
+
+ default_context = settings.DEFAULT_CONTEXT
+
+ # Function definitions
+ def walk_properties(cls):
+ bl_rna = cls.bl_rna
+ # Get our parents' properties, to not export them multiple times.
+ bl_rna_base = bl_rna.base
+ if bl_rna_base:
+ bl_rna_base_props = set(bl_rna_base.properties.values())
+ else:
+ bl_rna_base_props = set()
+
+ for prop in bl_rna.properties:
+ # Only write this property if our parent hasn't got it.
+ if prop in bl_rna_base_props:
+ continue
+ if prop.identifier == "rna_type":
+ continue
+ reports["rna_props"].append((cls, prop))
+
+ msgsrc = "bpy.types.{}.{}".format(bl_rna.identifier, prop.identifier)
+ msgctxt = prop.translation_context or default_context
+
+ if prop.name and (prop.name != prop.identifier or msgctxt != default_context):
+ process_msg(msgs, msgctxt, prop.name, msgsrc, reports, check_ctxt_rna, settings)
+ if prop.description:
+ process_msg(msgs, default_context, prop.description, msgsrc, reports, check_ctxt_rna_tip, settings)
+
+ if isinstance(prop, bpy.types.EnumProperty):
+ for item in prop.enum_items:
+ msgsrc = "bpy.types.{}.{}:'{}'".format(bl_rna.identifier, prop.identifier, 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)
+
+ blacklist_rna_class = class_blacklist()
+
+ def walk_class(cls):
+ bl_rna = cls.bl_rna
+ reports["rna_structs"].append(cls)
+ if bl_rna.identifier in blacklist_rna_class:
+ reports["rna_structs_skipped"].append(cls)
+ return
+
+ # XXX translation_context of Operator sub-classes are not "good"!
+ # So ignore those Operator sub-classes (anyway, will get the same from OperatorProperties sub-classes!)...
+ if issubclass(cls, bpy.types.Operator):
+ reports["rna_structs_skipped"].append(cls)
+ return
+
+ msgsrc = "bpy.types." + bl_rna.identifier
+ msgctxt = bl_rna.translation_context or default_context
+
+ if bl_rna.name and (bl_rna.name != bl_rna.identifier or msgctxt != default_context):
+ process_msg(msgs, msgctxt, bl_rna.name, msgsrc, reports, check_ctxt_rna, settings)
+
+ if bl_rna.description:
+ process_msg(msgs, default_context, bl_rna.description, msgsrc, reports, check_ctxt_rna_tip, settings)
+
+ if hasattr(bl_rna, 'bl_label') and bl_rna.bl_label:
+ process_msg(msgs, msgctxt, bl_rna.bl_label, msgsrc, reports, check_ctxt_rna, settings)
+
+ walk_properties(cls)
+
+ def walk_keymap_hierarchy(hier, msgsrc_prev):
+ for lvl in hier:
+ msgsrc = msgsrc_prev + "." + lvl[1]
+ process_msg(msgs, default_context, lvl[0], msgsrc, reports, None, settings)
+ if lvl[3]:
+ walk_keymap_hierarchy(lvl[3], msgsrc)
+
+ # Dump Messages
+ def process_cls_list(cls_list):
+ if not cls_list:
+ return
+
+ def full_class_id(cls):
+ """ gives us 'ID.Lamp.AreaLamp' which is best for sorting."""
+ cls_id = ""
+ bl_rna = cls.bl_rna
+ while bl_rna:
+ cls_id = bl_rna.identifier + "." + cls_id
+ bl_rna = bl_rna.base
+ return cls_id
+
+ cls_list.sort(key=full_class_id)
+ for cls in cls_list:
+ walk_class(cls)
+ # Recursively process subclasses.
+ process_cls_list(cls.__subclasses__())
+
+ # Parse everything (recursively parsing from bpy_struct "class"...).
+ process_cls_list(bpy.types.ID.__base__.__subclasses__())
+
+ # And parse keymaps!
+ from bpy_extras.keyconfig_utils import KM_HIERARCHY
+
+ walk_keymap_hierarchy(KM_HIERARCHY, "KM_HIERARCHY")
+
+
+##### Python source code #####
+def dump_py_messages_from_files(msgs, reports, files, settings):
+ """
+ Dump text inlined in the python files given, e.g. 'My Name' in:
+ layout.prop("someprop", text="My Name")
+ """
+ import ast
+
+ bpy_struct = bpy.types.ID.__base__
+
+ root_paths = tuple(bpy.utils.resource_path(t) for t in ('USER', 'LOCAL', 'SYSTEM'))
+ def make_rel(path):
+ for rp in root_paths:
+ if path.startswith(rp):
+ return os.path.relpath(path, rp)
+ # Use binary's dir as fallback...
+ return os.path.relpath(path, os.path.dirname(bpy.app.binary_path))
+
+ # Helper function
+ def extract_strings_ex(node, is_split=False):
+ """
+ Recursively get strings, needed in case we have "Blah" + "Blah", passed as an argument in that case it won't
+ evaluate to a string. However, break on some kind of stopper nodes, like e.g. Subscript.
+ """
+ if type(node) == ast.Str:
+ eval_str = ast.literal_eval(node)
+ if eval_str:
+ yield (is_split, eval_str, (node,))
+ else:
+ is_split = (type(node) in separate_nodes)
+ for nd in ast.iter_child_nodes(node):
+ if type(nd) not in stopper_nodes:
+ yield from extract_strings_ex(nd, is_split=is_split)
+
+ def _extract_string_merge(estr_ls, nds_ls):
+ return "".join(s for s in estr_ls if s is not None), tuple(n for n in nds_ls if n is not None)
+
+ def extract_strings(node):
+ estr_ls = []
+ nds_ls = []
+ for is_split, estr, nds in extract_strings_ex(node):
+ estr_ls.append(estr)
+ nds_ls.extend(nds)
+ ret = _extract_string_merge(estr_ls, nds_ls)
+ return ret
+
+ def extract_strings_split(node):
+ """
+ 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 = []
+ nds_ls = []
+ bag = []
+ for is_split, estr, nds in extract_strings_ex(node):
+ if is_split:
+ bag.append((estr_ls, nds_ls))
+ estr_ls = []
+ nds_ls = []
+
+ estr_ls.append(estr)
+ nds_ls.extend(nds)
+
+ bag.append((estr_ls, nds_ls))
+
+ return [_extract_string_merge(estr_ls, nds_ls) for estr_ls, nds_ls in bag]
+
+
+ def _ctxt_to_ctxt(node):
+ return extract_strings(node)[0]
+
+ def _op_to_ctxt(node):
+ opname, _ = extract_strings(node)
+ if not opname:
+ return settings.DEFAULT_CONTEXT
+ op = bpy.ops
+ for n in opname.split('.'):
+ op = getattr(op, n)
+ try:
+ return op.get_rna().bl_rna.translation_context
+ except Exception as e:
+ default_op_context = bpy.app.translations.contexts.operator_default
+ print("ERROR: ", str(e))
+ print(" Assuming default operator context '{}'".format(default_op_context))
+ return default_op_context
+
+ # Gather function names.
+ # In addition of UI func, also parse pgettext ones...
+ # Tuples of (module name, (short names, ...)).
+ pgettext_variants = (
+ ("pgettext", ("_",)),
+ ("pgettext_iface", ("iface_",)),
+ ("pgettext_tip", ("tip_",))
+ )
+ pgettext_variants_args = {"msgid": (0, {"msgctxt": 1})}
+
+ # key: msgid keywords.
+ # val: tuples of ((keywords,), context_getter_func) to get a context for that msgid.
+ # Note: order is important, first one wins!
+ translate_kw = {
+ "text": ((("text_ctxt",), _ctxt_to_ctxt),
+ (("operator",), _op_to_ctxt),
+ ),
+ "msgid": ((("msgctxt",), _ctxt_to_ctxt),
+ ),
+ }
+
+ context_kw_set = {}
+ for k, ctxts in translate_kw.items():
+ s = set()
+ for c, _ in ctxts:
+ s |= set(c)
+ context_kw_set[k] = s
+
+ # {func_id: {msgid: (arg_pos,
+ # {msgctxt: arg_pos,
+ # ...
+ # }
+ # ),
+ # ...
+ # },
+ # ...
+ # }
+ func_translate_args = {}
+
+ # First, functions from UILayout
+ # First loop is for msgid args, second one is for msgctxt args.
+ for func_id, func in bpy.types.UILayout.bl_rna.functions.items():
+ # check it has one or more arguments as defined in translate_kw
+ for arg_pos, (arg_kw, arg) in enumerate(func.parameters.items()):
+ if ((arg_kw in translate_kw) and (not arg.is_output) and (arg.type == 'STRING')):
+ func_translate_args.setdefault(func_id, {})[arg_kw] = (arg_pos, {})
+ for func_id, func in bpy.types.UILayout.bl_rna.functions.items():
+ if func_id not in func_translate_args:
+ continue
+ for arg_pos, (arg_kw, arg) in enumerate(func.parameters.items()):
+ if (not arg.is_output) and (arg.type == 'STRING'):
+ for msgid, msgctxts in context_kw_set.items():
+ if arg_kw in msgctxts:
+ func_translate_args[func_id][msgid][1][arg_kw] = arg_pos
+ # We manually add funcs from bpy.app.translations
+ for func_id, func_ids in pgettext_variants:
+ func_translate_args[func_id] = pgettext_variants_args
+ for func_id in func_ids:
+ func_translate_args[func_id] = pgettext_variants_args
+ #print(func_translate_args)
+
+ # Break recursive nodes look up on some kind of nodes.
+ # E.g. we don’t want to get strings inside subscripts (blah["foo"])!
+ stopper_nodes = {ast.Subscript}
+ # Consider strings separate: ("a" if test else "b")
+ separate_nodes = {ast.IfExp}
+
+ check_ctxt_py = None
+ if reports["check_ctxt"]:
+ check_ctxt = reports["check_ctxt"]
+ check_ctxt_py = {
+ "py_in_rna": (check_ctxt.get("py_in_rna"), set(msgs.keys())),
+ "multi_lines": check_ctxt.get("multi_lines"),
+ "not_capitalized": check_ctxt.get("not_capitalized"),
+ "end_point": check_ctxt.get("end_point"),
+ "spell_checker": check_ctxt.get("spell_checker"),
+ "spell_errors": check_ctxt.get("spell_errors"),
+ }
+
+ for fp in files:
+ with open(fp, 'r', encoding="utf8") as filedata:
+ root_node = ast.parse(filedata.read(), fp, 'exec')
+
+ fp_rel = make_rel(fp)
+
+ for node in ast.walk(root_node):
+ if type(node) == ast.Call:
+ # print("found function at")
+ # print("%s:%d" % (fp, node.lineno))
+
+ # We can't skip such situations! from blah import foo\nfoo("bar") would also be an ast.Name func!
+ if type(node.func) == ast.Name:
+ func_id = node.func.id
+ elif hasattr(node.func, "attr"):
+ func_id = node.func.attr
+ # Ugly things like getattr(self, con.type)(context, box, con)
+ else:
+ continue
+
+ func_args = func_translate_args.get(func_id, {})
+
+ # First try to get i18n contexts, for every possible msgid id.
+ msgctxts = dict.fromkeys(func_args.keys(), "")
+ for msgid, (_, context_args) in func_args.items():
+ context_elements = {}
+ for arg_kw, arg_pos in context_args.items():
+ if arg_pos < len(node.args):
+ context_elements[arg_kw] = node.args[arg_pos]
+ else:
+ for kw in node.keywords:
+ if kw.arg == arg_kw:
+ context_elements[arg_kw] = kw.value
+ break
+ #print(context_elements)
+ for kws, proc in translate_kw[msgid]:
+ if set(kws) <= context_elements.keys():
+ args = tuple(context_elements[k] for k in kws)
+ #print("running ", proc, " with ", args)
+ ctxt = proc(*args)
+ if ctxt:
+ msgctxts[msgid] = ctxt
+ break
+
+ #print(translate_args)
+ # do nothing if not found
+ for arg_kw, (arg_pos, _) in func_args.items():
+ msgctxt = msgctxts[arg_kw]
+ estr_lst = [(None, ())]
+ if arg_pos < len(node.args):
+ estr_lst = extract_strings_split(node.args[arg_pos])
+ #print(estr, nds)
+ else:
+ for kw in node.keywords:
+ if kw.arg == arg_kw:
+ estr_lst = extract_strings_split(kw.value)
+ break
+ #print(estr, nds)
+ for estr, nds in estr_lst:
+ if estr:
+ if nds:
+ msgsrc = "{}:{}".format(fp_rel, sorted({nd.lineno for nd in nds})[0])
+ else:
+ msgsrc = "{}:???".format(fp_rel)
+ process_msg(msgs, msgctxt, estr, msgsrc, reports, check_ctxt_py, settings)
+ reports["py_messages"].append((msgctxt, estr, msgsrc))
+
+
+def dump_py_messages(msgs, reports, addons, settings, addons_only=False):
+ def _get_files(path):
+ if not os.path.exists(path):
+ return []
+ if os.path.isdir(path):
+ return [os.path.join(dpath, fn) for dpath, _, fnames in os.walk(path) for fn in fnames
+ if not fn.startswith("_") and fn.endswith(".py")]
+ return [path]
+
+ files = []
+ if not addons_only:
+ for path in settings.CUSTOM_PY_UI_FILES:
+ for root in (bpy.utils.resource_path(t) for t in ('USER', 'LOCAL', 'SYSTEM')):
+ files += _get_files(os.path.join(root, path))
+
+ # Add all given addons.
+ for mod in addons:
+ fn = mod.__file__
+ if os.path.basename(fn) == "__init__.py":
+ files += _get_files(os.path.dirname(fn))
+ else:
+ files.append(fn)
+
+ dump_py_messages_from_files(msgs, reports, sorted(files), settings)
+
+
+##### C source code #####
+def dump_src_messages(msgs, reports, settings):
+ def get_contexts():
+ """Return a mapping {C_CTXT_NAME: ctxt_value}."""
+ return {k: getattr(bpy.app.translations.contexts, n) for k, n in bpy.app.translations.contexts_C_to_py.items()}
+
+ contexts = get_contexts()
+
+ # Build regexes to extract messages (with optional contexts) from C source.
+ pygettexts = tuple(re.compile(r).search for r in settings.PYGETTEXT_KEYWORDS)
+
+ _clean_str = re.compile(settings.str_clean_re).finditer
+ clean_str = lambda s: "".join(m.group("clean") for m in _clean_str(s))
+
+ def dump_src_file(path, rel_path, msgs, reports, settings):
+ def process_entry(_msgctxt, _msgid):
+ # Context.
+ msgctxt = settings.DEFAULT_CONTEXT
+ if _msgctxt:
+ if _msgctxt in contexts:
+ msgctxt = contexts[_msgctxt]
+ elif '"' in _msgctxt or "'" in _msgctxt:
+ msgctxt = clean_str(_msgctxt)
+ else:
+ print("WARNING: raw context “{}” couldn’t be resolved!".format(_msgctxt))
+ # Message.
+ msgid = ""
+ if _msgid:
+ if '"' in _msgid or "'" in _msgid:
+ msgid = clean_str(_msgid)
+ else:
+ print("WARNING: raw message “{}” couldn’t be resolved!".format(_msgid))
+ return msgctxt, msgid
+
+ check_ctxt_src = None
+ if reports["check_ctxt"]:
+ check_ctxt = reports["check_ctxt"]
+ check_ctxt_src = {
+ "multi_lines": check_ctxt.get("multi_lines"),
+ "not_capitalized": check_ctxt.get("not_capitalized"),
+ "end_point": check_ctxt.get("end_point"),
+ "spell_checker": check_ctxt.get("spell_checker"),
+ "spell_errors": check_ctxt.get("spell_errors"),
+ }
+
+ data = ""
+ with open(path) as f:
+ data = f.read()
+ for srch in pygettexts:
+ m = srch(data)
+ line = pos = 0
+ while m:
+ d = m.groupdict()
+ # Line.
+ line += data[pos:m.start()].count('\n')
+ msgsrc = rel_path + ":" + str(line)
+ _msgid = d.get("msg_raw")
+ # First, try the "multi-contexts" stuff!
+ _msgctxts = tuple(d.get("ctxt_raw{}".format(i)) for i in range(settings.PYGETTEXT_MAX_MULTI_CTXT))
+ if _msgctxts[0]:
+ for _msgctxt in _msgctxts:
+ if not _msgctxt:
+ break
+ msgctxt, msgid = process_entry(_msgctxt, _msgid)
+ process_msg(msgs, msgctxt, msgid, msgsrc, reports, check_ctxt_src, settings)
+ reports["src_messages"].append((msgctxt, msgid, msgsrc))
+ else:
+ _msgctxt = d.get("ctxt_raw")
+ msgctxt, msgid = process_entry(_msgctxt, _msgid)
+ process_msg(msgs, msgctxt, msgid, msgsrc, reports, check_ctxt_src, settings)
+ reports["src_messages"].append((msgctxt, msgid, msgsrc))
+
+ pos = m.end()
+ line += data[m.start():pos].count('\n')
+ m = srch(data, pos)
+
+ forbidden = set()
+ forced = set()
+ if os.path.isfile(settings.SRC_POTFILES):
+ with open(settings.SRC_POTFILES) as src:
+ for l in src:
+ if l[0] == '-':
+ forbidden.add(l[1:].rstrip('\n'))
+ elif l[0] != '#':
+ forced.add(l.rstrip('\n'))
+ for root, dirs, files in os.walk(settings.POTFILES_SOURCE_DIR):
+ if "/.svn" in root:
+ continue
+ for fname in files:
+ if os.path.splitext(fname)[1] not in settings.PYGETTEXT_ALLOWED_EXTS:
+ continue
+ path = os.path.join(root, fname)
+ rel_path = os.path.relpath(path, settings.SOURCE_DIR)
+ if rel_path in forbidden:
+ continue
+ elif rel_path not in forced:
+ forced.add(rel_path)
+ for rel_path in sorted(forced):
+ path = os.path.join(settings.SOURCE_DIR, rel_path)
+ if os.path.exists(path):
+ dump_src_file(path, rel_path, msgs, reports, settings)
+
+
+##### Main functions! #####
+def dump_messages(do_messages, do_checks, settings):
+ bl_ver = "Blender " + bpy.app.version_string
+ bl_rev = bpy.app.build_revision
+ bl_date = datetime.datetime.strptime(bpy.app.build_date.decode() + "T" + bpy.app.build_time.decode(),
+ "%Y-%m-%dT%H:%M:%S")
+ pot = utils.I18nMessages.gen_empty_messages(settings.PARSER_TEMPLATE_ID, bl_ver, bl_rev, bl_date, bl_date.year,
+ settings=settings)
+ msgs = pot.msgs
+
+ # Enable all wanted addons.
+ # For now, enable all official addons, before extracting msgids.
+ addons = enable_addons(support={"OFFICIAL"})
+ # Note this is not needed if we have been started with factory settings, but just in case...
+ enable_addons(support={"COMMUNITY", "TESTING"}, disable=True)
+
+ reports = _gen_reports(_gen_check_ctxt(settings) if do_checks else None)
+
+ # Get strings from RNA.
+ dump_messages_rna(msgs, reports, settings)
+
+ # Get strings from UI layout definitions text="..." args.
+ dump_py_messages(msgs, reports, addons, settings)
+
+ # Get strings from C source code.
+ dump_src_messages(msgs, reports, settings)
+
+ # Get strings from addons' categories.
+ for uid, label, tip in bpy.types.WindowManager.addon_filter[1]['items'](bpy.context.window_manager, bpy.context):
+ process_msg(msgs, settings.DEFAULT_CONTEXT, label, "Addons' categories", reports, None, settings)
+ if tip:
+ process_msg(msgs, settings.DEFAULT_CONTEXT, tip, "Addons' categories", reports, None, settings)
+
+ # Get strings specific to translations' menu.
+ for lng in settings.LANGUAGES:
+ process_msg(msgs, settings.DEFAULT_CONTEXT, lng[1], "Languages’ labels from bl_i18n_utils/settings.py",
+ reports, None, settings)
+ for cat in settings.LANGUAGES_CATEGORIES:
+ process_msg(msgs, settings.DEFAULT_CONTEXT, cat[1],
+ "Language categories’ labels from bl_i18n_utils/settings.py", reports, None, settings)
+
+ #pot.check()
+ pot.unescape() # Strings gathered in py/C source code may contain escaped chars...
+ print_info(reports, pot)
+ #pot.check()
+
+ if do_messages:
+ print("Writing messages…")
+ pot.write('PO', settings.FILE_NAME_POT)
+
+ print("Finished extracting UI messages!")
+
+
+def dump_addon_messages(module_name, messages_formats, do_checks, settings):
+ # Enable our addon and get strings from RNA.
+ addon = enable_addons(addons={module_name})[0]
+
+ addon_info = addon_utils.module_bl_info(addon)
+ ver = addon_info.name + " " + ".".join(addon_info.version)
+ rev = "???"
+ date = datetime.datetime()
+ pot = utils.I18nMessages.gen_empty_messages(settings.PARSER_TEMPLATE_ID, ver, rev, date, date.year,
+ settings=settings)
+ msgs = pot.msgs
+
+ minus_msgs = copy.deepcopy(msgs)
+
+ check_ctxt = _gen_check_ctxt(settings) if do_checks else None
+ minus_check_ctxt = _gen_check_ctxt(settings) if do_checks else None
+
+ # Get current addon state (loaded or not):
+ was_loaded = addon_utils.check(module_name)[1]
+
+ # Enable our addon and get strings from RNA.
+ addons = enable_addons(addons={module_name})
+ reports = _gen_reports(check_ctxt)
+ dump_messages_rna(msgs, reports, settings)
+
+ # Now disable our addon, and rescan RNA.
+ enable_addons(addons={module_name}, disable=True)
+ reports["check_ctxt"] = minus_check_ctxt
+ dump_messages_rna(minus_msgs, reports, settings)
+
+ # Restore previous state if needed!
+ if was_loaded:
+ enable_addons(addons={module_name})
+
+ # and make the diff!
+ for key in minus_msgs:
+ if key == settings.PO_HEADER_KEY:
+ continue
+ del msgs[key]
+
+ if check_ctxt:
+ for key in check_ctxt:
+ for warning in minus_check_ctxt[key]:
+ check_ctxt[key].remove(warning)
+
+ # and we are done with those!
+ del minus_msgs
+ del minus_check_ctxt
+
+ # get strings from UI layout definitions text="..." args
+ reports["check_ctxt"] = check_ctxt
+ dump_messages_pytext(msgs, reports, addons, settings, addons_only=True)
+
+ print_info(reports, pot)
+
+ return pot
+
+
+def main():
+ try:
+ import bpy
+ except ImportError:
+ print("This script must run from inside blender")
+ return
+
+ import sys
+ back_argv = sys.argv
+ # Get rid of Blender args!
+ sys.argv = sys.argv[sys.argv.index("--") + 1:]
+
+ import argparse
+ parser = argparse.ArgumentParser(description="Process UI messages from inside Blender.")
+ parser.add_argument('-c', '--no_checks', default=True, action="store_false", help="No checks over UI messages.")
+ parser.add_argument('-m', '--no_messages', default=True, action="store_false", help="No export of UI messages.")
+ parser.add_argument('-o', '--output', default=None, help="Output POT file path.")
+ parser.add_argument('-s', '--settings', default=None,
+ help="Override (some) default settings. Either a JSon file name, or a JSon string.")
+ args = parser.parse_args()
+
+ settings = i18n_settings.I18nSettings()
+ settings.from_json(args.settings)
+
+ if args.output:
+ settings.FILE_NAME_POT = args.output
+
+ dump_messages(do_messages=args.no_messages, do_checks=args.no_checks, settings=settings)
+
+ sys.argv = back_argv
+
+
+if __name__ == "__main__":
+ print("\n\n *** Running {} *** \n".format(__file__))
+ main()
diff --git a/release/scripts/modules/bl_i18n_utils/bl_process_msg.py b/release/scripts/modules/bl_i18n_utils/bl_process_msg.py
deleted file mode 100644
index 006d7170571..00000000000
--- a/release/scripts/modules/bl_i18n_utils/bl_process_msg.py
+++ /dev/null
@@ -1,762 +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.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-# <pep8 compliant>
-
-# Write out messages.txt from Blender.
-# XXX: This script is meant to be used from inside Blender!
-# You should not directly use this script, rather use update_msg.py!
-
-import os
-import re
-import collections
-import copy
-
-# XXX Relative import does not work here when used from Blender...
-from bl_i18n_utils import settings
-
-import bpy
-
-print(dir(settings))
-
-SOURCE_DIR = settings.SOURCE_DIR
-
-CUSTOM_PY_UI_FILES = [os.path.abspath(os.path.join(SOURCE_DIR, p)) for p in settings.CUSTOM_PY_UI_FILES]
-FILE_NAME_MESSAGES = settings.FILE_NAME_MESSAGES
-MSG_COMMENT_PREFIX = settings.MSG_COMMENT_PREFIX
-MSG_CONTEXT_PREFIX = settings.MSG_CONTEXT_PREFIX
-CONTEXT_DEFAULT = settings.CONTEXT_DEFAULT
-#CONTEXT_DEFAULT = bpy.app.i18n.contexts.default # XXX Not yet! :)
-UNDOC_OPS_STR = settings.UNDOC_OPS_STR
-
-NC_ALLOWED = settings.WARN_MSGID_NOT_CAPITALIZED_ALLOWED
-
-
-##### Utils #####
-
-# check for strings like ": %d"
-ignore_reg = re.compile(r"^(?:[-*.()/\\+:%xWXYZ0-9]|%d|%f|%s|%r|\s)*$")
-filter_message = ignore_reg.match
-
-
-def check(check_ctxt, messages, key, msgsrc):
- """
- Performs a set of checks over the given key (context, message)...
- """
- if check_ctxt is None:
- return
- multi_rnatip = check_ctxt.get("multi_rnatip")
- multi_lines = check_ctxt.get("multi_lines")
- py_in_rna = check_ctxt.get("py_in_rna")
- not_capitalized = check_ctxt.get("not_capitalized")
- end_point = check_ctxt.get("end_point")
- undoc_ops = check_ctxt.get("undoc_ops")
-
- if multi_rnatip is not None:
- if key in messages and key not in multi_rnatip:
- multi_rnatip.add(key)
- if multi_lines is not None:
- if '\n' in key[1]:
- multi_lines.add(key)
- if py_in_rna is not None:
- if key in py_in_rna[1]:
- py_in_rna[0].add(key)
- if not_capitalized is not None:
- if(key[1] not in NC_ALLOWED and key[1][0].isalpha() and not key[1][0].isupper()):
- not_capitalized.add(key)
- if end_point is not None:
- if key[1].strip().endswith('.'):
- end_point.add(key)
- if undoc_ops is not None:
- if key[1] == UNDOC_OPS_STR:
- undoc_ops.add(key)
-
-
-def print_warnings(check_ctxt, messages):
- if check_ctxt is not None:
- print("WARNINGS:")
- keys = set()
- for c in check_ctxt.values():
- keys |= c
- # XXX Temp, see below
- keys -= check_ctxt["multi_rnatip"]
- for key in keys:
- if key in check_ctxt["undoc_ops"]:
- print("\tThe following operators are undocumented:")
- else:
- print("\t“{}”|“{}”:".format(*key))
- if key in check_ctxt["multi_lines"]:
- print("\t\t-> newline in this message!")
- if key in check_ctxt["not_capitalized"]:
- print("\t\t-> message not capitalized!")
- if key in check_ctxt["end_point"]:
- print("\t\t-> message with endpoint!")
- # XXX Hide this one for now, too much false positives.
-# if key in check_ctxt["multi_rnatip"]:
-# print("\t\t-> tip used in several RNA items")
- if key in check_ctxt["py_in_rna"]:
- print("\t\t-> RNA message also used in py UI code:")
- print("\t\t{}".format("\n\t\t".join(messages[key])))
-
-
-def enable_addons(addons={}, support={}, disable=False):
- """
- Enable (or disable) addons based either on a set of names, or a set of 'support' types.
- Returns the list of all affected addons (as fake modules)!
- """
- import addon_utils
- import bpy
-
- userpref = bpy.context.user_preferences
- used_ext = {ext.module for ext in userpref.addons}
-
- ret = [mod for mod in addon_utils.modules(addon_utils.addons_fake_modules)
- if ((addons and mod.__name__ in addons) or
- (not addons and addon_utils.module_bl_info(mod)["support"] in support))]
-
- for mod in ret:
- module_name = mod.__name__
- if disable:
- if module_name not in used_ext:
- continue
- print(" Disabling module ", module_name)
- bpy.ops.wm.addon_disable(module=module_name)
- else:
- if module_name in used_ext:
- continue
- print(" Enabling module ", module_name)
- bpy.ops.wm.addon_enable(module=module_name)
-
- # XXX There are currently some problems with bpy/rna...
- # *Very* tricky to solve!
- # So this is a hack to make all newly added operator visible by
- # bpy.types.OperatorProperties.__subclasses__()
- for cat in dir(bpy.ops):
- cat = getattr(bpy.ops, cat)
- for op in dir(cat):
- getattr(cat, op).get_rna()
-
- return ret
-
-
-##### RNA #####
-
-def dump_messages_rna(messages, check_ctxt):
- """
- Dump into messages dict all RNA-defined UI messages (labels en tooltips).
- """
- import bpy
-
- def classBlackList():
- blacklist_rna_class = [
- # core classes
- "Context", "Event", "Function", "UILayout", "BlendData",
- # registerable classes
- "Panel", "Menu", "Header", "RenderEngine", "Operator", "OperatorMacro", "Macro",
- "KeyingSetInfo", "UnknownType",
- # window classes
- "Window",
- ]
-
- # ---------------------------------------------------------------------
- # Collect internal operators
-
- # extend with all internal operators
- # note that this uses internal api introspection functions
- # all possible operator names
- op_ids = set(cls.bl_rna.identifier for cls in bpy.types.OperatorProperties.__subclasses__()) | \
- set(cls.bl_rna.identifier for cls in bpy.types.Operator.__subclasses__()) | \
- set(cls.bl_rna.identifier for cls in bpy.types.OperatorMacro.__subclasses__())
-
- get_instance = __import__("_bpy").ops.get_instance
- path_resolve = type(bpy.context).__base__.path_resolve
- for idname in op_ids:
- op = get_instance(idname)
- # XXX Do not skip INTERNAL's anymore, some of those ops show up in UI now!
-# if 'INTERNAL' in path_resolve(op, "bl_options"):
-# blacklist_rna_class.append(idname)
-
- # ---------------------------------------------------------------------
- # Collect builtin classes we don't need to doc
- blacklist_rna_class.append("Property")
- blacklist_rna_class.extend([cls.__name__ for cls in bpy.types.Property.__subclasses__()])
-
- # ---------------------------------------------------------------------
- # Collect classes which are attached to collections, these are api
- # access only.
- collection_props = set()
- for cls_id in dir(bpy.types):
- cls = getattr(bpy.types, cls_id)
- for prop in cls.bl_rna.properties:
- if prop.type == 'COLLECTION':
- prop_cls = prop.srna
- if prop_cls is not None:
- collection_props.add(prop_cls.identifier)
- blacklist_rna_class.extend(sorted(collection_props))
-
- return blacklist_rna_class
-
- blacklist_rna_class = classBlackList()
-
- def filterRNA(bl_rna):
- rid = bl_rna.identifier
- if rid in blacklist_rna_class:
- print(" skipping", rid)
- return True
- return False
-
- check_ctxt_rna = check_ctxt_rna_tip = None
- if check_ctxt:
- check_ctxt_rna = {"multi_lines": check_ctxt.get("multi_lines"),
- "not_capitalized": check_ctxt.get("not_capitalized"),
- "end_point": check_ctxt.get("end_point"),
- "undoc_ops": check_ctxt.get("undoc_ops")}
- check_ctxt_rna_tip = check_ctxt_rna
- check_ctxt_rna_tip["multi_rnatip"] = check_ctxt.get("multi_rnatip")
-
- # -------------------------------------------------------------------------
- # Function definitions
-
- def walkProperties(bl_rna):
- import bpy
-
- # Get our parents' properties, to not export them multiple times.
- bl_rna_base = bl_rna.base
- if bl_rna_base:
- bl_rna_base_props = bl_rna_base.properties.values()
- else:
- bl_rna_base_props = ()
-
- for prop in bl_rna.properties:
- # Only write this property if our parent hasn't got it.
- if prop in bl_rna_base_props:
- continue
- if prop.identifier == "rna_type":
- continue
-
- msgsrc = "bpy.types.{}.{}".format(bl_rna.identifier, prop.identifier)
- context = getattr(prop, "translation_context", CONTEXT_DEFAULT)
- if prop.name and (prop.name != prop.identifier or context):
- key = (context, prop.name)
- check(check_ctxt_rna, messages, key, msgsrc)
- messages.setdefault(key, []).append(msgsrc)
- if prop.description:
- key = (CONTEXT_DEFAULT, prop.description)
- check(check_ctxt_rna_tip, messages, key, msgsrc)
- messages.setdefault(key, []).append(msgsrc)
- if isinstance(prop, bpy.types.EnumProperty):
- for item in prop.enum_items:
- msgsrc = "bpy.types.{}.{}:'{}'".format(bl_rna.identifier,
- prop.identifier,
- item.identifier)
- if item.name and item.name != item.identifier:
- key = (CONTEXT_DEFAULT, item.name)
- check(check_ctxt_rna, messages, key, msgsrc)
- messages.setdefault(key, []).append(msgsrc)
- if item.description:
- key = (CONTEXT_DEFAULT, item.description)
- check(check_ctxt_rna_tip, messages, key, msgsrc)
- messages.setdefault(key, []).append(msgsrc)
-
- def walkRNA(bl_rna):
- if filterRNA(bl_rna):
- return
-
- msgsrc = ".".join(("bpy.types", bl_rna.identifier))
- context = getattr(bl_rna, "translation_context", CONTEXT_DEFAULT)
-
- if bl_rna.name and (bl_rna.name != bl_rna.identifier or context):
- key = (context, bl_rna.name)
- check(check_ctxt_rna, messages, key, msgsrc)
- messages.setdefault(key, []).append(msgsrc)
-
- if bl_rna.description:
- key = (CONTEXT_DEFAULT, bl_rna.description)
- check(check_ctxt_rna_tip, messages, key, msgsrc)
- messages.setdefault(key, []).append(msgsrc)
-
- if hasattr(bl_rna, 'bl_label') and bl_rna.bl_label:
- key = (context, bl_rna.bl_label)
- check(check_ctxt_rna, messages, key, msgsrc)
- messages.setdefault(key, []).append(msgsrc)
-
- walkProperties(bl_rna)
-
- def walkClass(cls):
- walkRNA(cls.bl_rna)
-
- def walk_keymap_hierarchy(hier, msgsrc_prev):
- for lvl in hier:
- msgsrc = "{}.{}".format(msgsrc_prev, lvl[1])
- messages.setdefault((CONTEXT_DEFAULT, lvl[0]), []).append(msgsrc)
-
- if lvl[3]:
- walk_keymap_hierarchy(lvl[3], msgsrc)
-
- # -------------------------------------------------------------------------
- # Dump Messages
-
- def process_cls_list(cls_list):
- if not cls_list:
- return 0
-
- def full_class_id(cls):
- """ gives us 'ID.Lamp.AreaLamp' which is best for sorting.
- """
- cls_id = ""
- bl_rna = cls.bl_rna
- while bl_rna:
- cls_id = "{}.{}".format(bl_rna.identifier, cls_id)
- bl_rna = bl_rna.base
- return cls_id
-
- cls_list.sort(key=full_class_id)
- processed = 0
- for cls in cls_list:
- # XXX translation_context of Operator sub-classes are not "good"!
- # So ignore those Operator sub-classes (anyway, will get the same from OperatorProperties
- # sub-classes!)...
- if issubclass(cls, bpy.types.Operator):
- continue
-
- walkClass(cls)
-# classes.add(cls)
- # Recursively process subclasses.
- processed += process_cls_list(cls.__subclasses__()) + 1
- return processed
-
- # Parse everything (recursively parsing from bpy_struct "class"...).
- processed = process_cls_list(type(bpy.context).__base__.__subclasses__())
- print("{} classes processed!".format(processed))
-
- from bpy_extras.keyconfig_utils import KM_HIERARCHY
-
- walk_keymap_hierarchy(KM_HIERARCHY, "KM_HIERARCHY")
-
-
-##### Python source code #####
-
-def dump_py_messages_from_files(messages, check_ctxt, files):
- """
- Dump text inlined in the python files given, e.g. 'My Name' in:
- layout.prop("someprop", text="My Name")
- """
- import ast
-
- bpy_struct = bpy.types.ID.__base__
-
- # Helper function
- def extract_strings_ex(node, is_split=False):
- """
- Recursively get strings, needed in case we have "Blah" + "Blah", passed as an argument in that case it won't
- evaluate to a string. However, break on some kind of stopper nodes, like e.g. Subscript.
- """
-
- if type(node) == ast.Str:
- eval_str = ast.literal_eval(node)
- if eval_str:
- yield (is_split, eval_str, (node,))
- else:
- is_split = (type(node) in separate_nodes)
- for nd in ast.iter_child_nodes(node):
- if type(nd) not in stopper_nodes:
- yield from extract_strings_ex(nd, is_split=is_split)
-
- def _extract_string_merge(estr_ls, nds_ls):
- return "".join(s for s in estr_ls if s is not None), tuple(n for n in nds_ls if n is not None)
-
- def extract_strings(node):
- estr_ls = []
- nds_ls = []
- for is_split, estr, nds in extract_strings_ex(node):
- estr_ls.append(estr)
- nds_ls.extend(nds)
- ret = _extract_string_merge(estr_ls, nds_ls)
- #print(ret)
- return ret
-
- def extract_strings_split(node):
- """
- 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 = []
- nds_ls = []
- bag = []
- for is_split, estr, nds in extract_strings_ex(node):
- if is_split:
- bag.append((estr_ls, nds_ls))
- estr_ls = []
- nds_ls = []
-
- estr_ls.append(estr)
- nds_ls.extend(nds)
-
- bag.append((estr_ls, nds_ls))
-
- return [_extract_string_merge(estr_ls, nds_ls) for estr_ls, nds_ls in bag]
-
-
- def _ctxt_to_ctxt(node):
- return extract_strings(node)[0]
-
- def _op_to_ctxt(node):
- opname, _ = extract_strings(node)
- if not opname:
- return ""
- op = bpy.ops
- for n in opname.split('.'):
- op = getattr(op, n)
- try:
- return op.get_rna().bl_rna.translation_context
- except Exception as e:
- default_op_context = bpy.app.translations.contexts.operator_default
- print("ERROR: ", str(e))
- print(" Assuming default operator context '{}'".format(default_op_context))
- return default_op_context
-
- # -------------------------------------------------------------------------
- # Gather function names
-
- # In addition of UI func, also parse pgettext ones...
- # Tuples of (module name, (short names, ...)).
- pgettext_variants = (
- ("pgettext", ("_",)),
- ("pgettext_iface", ("iface_",)),
- ("pgettext_tip", ("tip_",))
- )
- pgettext_variants_args = {"msgid": (0, {"msgctxt": 1})}
-
- # key: msgid keywords.
- # val: tuples of ((keywords,), context_getter_func) to get a context for that msgid.
- # Note: order is important, first one wins!
- translate_kw = {
- "text": ((("text_ctxt",), _ctxt_to_ctxt),
- (("operator",), _op_to_ctxt),
- ),
- "msgid": ((("msgctxt",), _ctxt_to_ctxt),
- ),
- }
-
- context_kw_set = {}
- for k, ctxts in translate_kw.items():
- s = set()
- for c, _ in ctxts:
- s |= set(c)
- context_kw_set[k] = s
-
- # {func_id: {msgid: (arg_pos,
- # {msgctxt: arg_pos,
- # ...
- # }
- # ),
- # ...
- # },
- # ...
- # }
- func_translate_args = {}
-
- # First, functions from UILayout
- # First loop is for msgid args, second one is for msgctxt args.
- for func_id, func in bpy.types.UILayout.bl_rna.functions.items():
- # check it has one or more arguments as defined in translate_kw
- for arg_pos, (arg_kw, arg) in enumerate(func.parameters.items()):
- if ((arg_kw in translate_kw) and (not arg.is_output) and (arg.type == 'STRING')):
- func_translate_args.setdefault(func_id, {})[arg_kw] = (arg_pos, {})
- for func_id, func in bpy.types.UILayout.bl_rna.functions.items():
- if func_id not in func_translate_args:
- continue
- for arg_pos, (arg_kw, arg) in enumerate(func.parameters.items()):
- if (not arg.is_output) and (arg.type == 'STRING'):
- for msgid, msgctxts in context_kw_set.items():
- if arg_kw in msgctxts:
- func_translate_args[func_id][msgid][1][arg_kw] = arg_pos
- # We manually add funcs from bpy.app.translations
- for func_id, func_ids in pgettext_variants:
- func_translate_args[func_id] = pgettext_variants_args
- for func_id in func_ids:
- func_translate_args[func_id] = pgettext_variants_args
- #print(func_translate_args)
-
- # Break recursive nodes look up on some kind of nodes.
- # E.g. we don’t want to get strings inside subscripts (blah["foo"])!
- stopper_nodes = {ast.Subscript}
- # Consider strings separate: ("a" if test else "b")
- separate_nodes = {ast.IfExp}
-
- check_ctxt_py = None
- if check_ctxt:
- check_ctxt_py = {"py_in_rna": (check_ctxt["py_in_rna"], messages.copy()),
- "multi_lines": check_ctxt["multi_lines"],
- "not_capitalized": check_ctxt["not_capitalized"],
- "end_point": check_ctxt["end_point"]}
-
- for fp in files:
- with open(fp, 'r', encoding="utf8") as filedata:
- root_node = ast.parse(filedata.read(), fp, 'exec')
-
- fp_rel = os.path.relpath(fp, SOURCE_DIR)
-
- for node in ast.walk(root_node):
- if type(node) == ast.Call:
- # print("found function at")
- # print("%s:%d" % (fp, node.lineno))
-
- # We can't skip such situations! from blah import foo\nfoo("bar") would also be an ast.Name func!
- if type(node.func) == ast.Name:
- func_id = node.func.id
- elif hasattr(node.func, "attr"):
- func_id = node.func.attr
- # Ugly things like getattr(self, con.type)(context, box, con)
- else:
- continue
-
- func_args = func_translate_args.get(func_id, {})
-
- # First try to get i18n contexts, for every possible msgid id.
- contexts = dict.fromkeys(func_args.keys(), "")
- for msgid, (_, context_args) in func_args.items():
- context_elements = {}
- for arg_kw, arg_pos in context_args.items():
- if arg_pos < len(node.args):
- context_elements[arg_kw] = node.args[arg_pos]
- else:
- for kw in node.keywords:
- if kw.arg == arg_kw:
- context_elements[arg_kw] = kw.value
- break
- #print(context_elements)
- for kws, proc in translate_kw[msgid]:
- if set(kws) <= context_elements.keys():
- args = tuple(context_elements[k] for k in kws)
- #print("running ", proc, " with ", args)
- ctxt = proc(*args)
- if ctxt:
- contexts[msgid] = ctxt
- break
-
- #print(translate_args)
- # do nothing if not found
- for arg_kw, (arg_pos, _) in func_args.items():
- estr_lst = [(None, ())]
- if arg_pos < len(node.args):
- estr_lst = extract_strings_split(node.args[arg_pos])
- #print(estr, nds)
- else:
- for kw in node.keywords:
- if kw.arg == arg_kw:
- estr_lst = extract_strings_split(kw.value)
- break
- #print(estr, nds)
- for estr, nds in estr_lst:
- if estr:
- key = (contexts[arg_kw], estr)
- if nds:
- msgsrc = ["{}:{}".format(fp_rel, sorted({nd.lineno for nd in nds})[0])]
- else:
- msgsrc = ["{}:???".format(fp_rel)]
- check(check_ctxt_py, messages, key, msgsrc)
- messages.setdefault(key, []).extend(msgsrc)
-
-
-def dump_py_messages(messages, check_ctxt, addons):
- mod_dir = os.path.join(SOURCE_DIR, "release", "scripts", "startup", "bl_ui")
-
- files = [os.path.join(mod_dir, fn) for fn in sorted(os.listdir(mod_dir))
- if not fn.startswith("_") if fn.endswith("py")]
-
- # Dummy Cycles has its py addon in its own dir!
- files += CUSTOM_PY_UI_FILES
-
- # Add all addons we support in main translation file!
- for mod in addons:
- fn = mod.__file__
- if os.path.basename(fn) == "__init__.py":
- mod_dir = os.path.dirname(fn)
- files += [fn for fn in sorted(os.listdir(mod_dir))
- if os.path.isfile(fn) and os.path.splitext(fn)[1] == ".py"]
- else:
- files.append(fn)
-
- dump_py_messages_from_files(messages, check_ctxt, files)
-
-
-##### Main functions! #####
-
-def dump_messages(do_messages, do_checks):
- messages = getattr(collections, 'OrderedDict', dict)()
-
- messages[(CONTEXT_DEFAULT, "")] = []
-
- # Enable all wanted addons.
- # For now, enable all official addons, before extracting msgids.
- addons = enable_addons(support={"OFFICIAL"})
-
- check_ctxt = None
- if do_checks:
- check_ctxt = {"multi_rnatip": set(),
- "multi_lines": set(),
- "py_in_rna": set(),
- "not_capitalized": set(),
- "end_point": set(),
- "undoc_ops": set()}
-
- # get strings from RNA
- dump_messages_rna(messages, check_ctxt)
-
- # get strings from UI layout definitions text="..." args
- dump_py_messages(messages, check_ctxt, addons)
-
- del messages[(CONTEXT_DEFAULT, "")]
-
- print_warnings(check_ctxt, messages)
-
- if do_messages:
- print("Writing messages…")
- num_written = 0
- num_filtered = 0
- with open(FILE_NAME_MESSAGES, 'w', encoding="utf8") as message_file:
- for (ctx, key), value in messages.items():
- # filter out junk values
- if filter_message(key):
- num_filtered += 1
- continue
-
- # Remove newlines in key and values!
- message_file.write("\n".join(MSG_COMMENT_PREFIX + msgsrc.replace("\n", "") for msgsrc in value))
- message_file.write("\n")
- if ctx:
- message_file.write(MSG_CONTEXT_PREFIX + ctx.replace("\n", "") + "\n")
- message_file.write(key.replace("\n", "") + "\n")
- num_written += 1
-
- print("Written {} messages to: {} ({} were filtered out)."
- "".format(num_written, FILE_NAME_MESSAGES, num_filtered))
-
-
-def dump_addon_messages(module_name, messages_formats, do_checks):
- messages = getattr(collections, 'OrderedDict', dict)()
-
- messages[(CONTEXT_DEFAULT, "")] = []
- minus_messages = copy.deepcopy(messages)
-
- check_ctxt = None
- minus_check_ctxt = None
- if do_checks:
- check_ctxt = {"multi_rnatip": set(),
- "multi_lines": set(),
- "py_in_rna": set(),
- "not_capitalized": set(),
- "end_point": set(),
- "undoc_ops": set()}
- minus_check_ctxt = copy.deepcopy(check_ctxt)
-
- # Get current addon state (loaded or not):
- was_loaded = addon_utils.check(module_name)[1]
-
- # Enable our addon and get strings from RNA.
- enable_addons(addons={module_name})
- dump_messages_rna(messages, check_ctxt)
-
- # Now disable our addon, and rescan RNA.
- enable_addons(addons={module_name}, disable=True)
- dump_messages_rna(minus_messages, minus_check_ctxt)
-
- # Restore previous state if needed!
- if was_loaded:
- enable_addons(addons={module_name})
-
- # and make the diff!
- for key in minus_messages:
- if k == (CONTEXT_DEFAULT, ""):
- continue
- del messages[k]
-
- if check_ctxt:
- for key in check_ctxt:
- for warning in minus_check_ctxt[key]:
- check_ctxt[key].remove(warning)
-
- # and we are done with those!
- del minus_messages
- del minus_check_ctxt
-
- # get strings from UI layout definitions text="..." args
- dump_messages_pytext(messages, check_ctxt)
-
- del messages[(CONTEXT_DEFAULT, "")]
-
- print_warnings
-
- if do_messages:
- print("Writing messages…")
- num_written = 0
- num_filtered = 0
- with open(FILE_NAME_MESSAGES, 'w', encoding="utf8") as message_file:
- for (ctx, key), value in messages.items():
- # filter out junk values
- if filter_message(key):
- num_filtered += 1
- continue
-
- # Remove newlines in key and values!
- message_file.write("\n".join(COMMENT_PREFIX + msgsrc.replace("\n", "") for msgsrc in value))
- message_file.write("\n")
- if ctx:
- message_file.write(CONTEXT_PREFIX + ctx.replace("\n", "") + "\n")
- message_file.write(key.replace("\n", "") + "\n")
- num_written += 1
-
- print("Written {} messages to: {} ({} were filtered out)."
- "".format(num_written, FILE_NAME_MESSAGES, num_filtered))
-
-
-
-def main():
- try:
- import bpy
- except ImportError:
- print("This script must run from inside blender")
- return
-
- import sys
- back_argv = sys.argv
- # Get rid of Blender args!
- sys.argv = sys.argv[sys.argv.index("--") + 1:]
-
- import argparse
- parser = argparse.ArgumentParser(description="Process UI messages from inside Blender.")
- parser.add_argument('-c', '--no_checks', default=True, action="store_false", help="No checks over UI messages.")
- parser.add_argument('-m', '--no_messages', default=True, action="store_false", help="No export of UI messages.")
- parser.add_argument('-o', '--output', help="Output messages file path.")
- args = parser.parse_args()
-
- if args.output:
- global FILE_NAME_MESSAGES
- FILE_NAME_MESSAGES = args.output
-
- dump_messages(do_messages=args.no_messages, do_checks=args.no_checks)
-
- sys.argv = back_argv
-
-
-if __name__ == "__main__":
- print("\n\n *** Running {} *** \n".format(__file__))
- main()
diff --git a/release/scripts/modules/bl_i18n_utils/languages_menu_utils.py b/release/scripts/modules/bl_i18n_utils/languages_menu_utils.py
new file mode 100755
index 00000000000..789b1315659
--- /dev/null
+++ b/release/scripts/modules/bl_i18n_utils/languages_menu_utils.py
@@ -0,0 +1,96 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public 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>
+
+# Update "languages" text file used by Blender at runtime to build translations menu.
+
+
+import os
+
+
+OK = 0
+MISSING = 1
+TOOLOW = 2
+FORBIDDEN = 3
+FLAG_MESSAGES = {
+ OK: "",
+ MISSING: "No translation yet!",
+ TOOLOW: "Not enough advanced to be included...",
+ FORBIDDEN: "Explicitly forbidden!",
+}
+
+def gen_menu_file(stats, settings):
+ # Generate languages file used by Blender's i18n system.
+ # First, match all entries in LANGUAGES to a lang in stats, if possible!
+ tmp = []
+ for uid_num, label, uid, in settings.LANGUAGES:
+ if uid in stats:
+ if uid in settings.IMPORT_LANGUAGES_SKIP:
+ tmp.append((stats[uid], uid_num, label, uid, FORBIDDEN))
+ else:
+ tmp.append((stats[uid], uid_num, label, uid, OK))
+ else:
+ tmp.append((0.0, uid_num, label, uid, MISSING))
+ stats = tmp
+ limits = sorted(settings.LANGUAGES_CATEGORIES, key=lambda it: it[0], reverse=True)
+ idx = 0
+ stats = sorted(stats, key=lambda it: it[0], reverse=True)
+ langs_cats = [[] for i in range(len(limits))]
+ highest_uid = 0
+ for lvl, uid_num, label, uid, flag in stats:
+ if lvl < limits[idx][0]:
+ # Sub-sort languages by iso-codes.
+ langs_cats[idx].sort(key=lambda it: it[2])
+ idx += 1
+ if lvl < settings.IMPORT_MIN_LEVEL and flag == OK:
+ flag = TOOLOW
+ langs_cats[idx].append((uid_num, label, uid, flag))
+ if abs(uid_num) > highest_uid:
+ highest_uid = abs(uid_num)
+ # Sub-sort last group of languages by iso-codes!
+ langs_cats[idx].sort(key=lambda it: it[2])
+ data_lines = [
+ "# File used by Blender to know which languages (translations) are available, ",
+ "# and to generate translation menu.",
+ "#",
+ "# File format:",
+ "# ID:MENULABEL:ISOCODE",
+ "# ID must be unique, except for 0 value (marks categories for menu).",
+ "# Line starting with a # are comments!",
+ "#",
+ "# Automatically generated by bl_i18n_utils/update_languages_menu.py script.",
+ "# Highest ID currently in use: {}".format(highest_uid),
+ ]
+ for cat, langs_cat in zip(limits, langs_cats):
+ data_lines.append("#")
+ # Write "category menu label"...
+ if langs_cat:
+ data_lines.append("0:{}:".format(cat[1]))
+ else:
+ # Do not write the category if it has no language!
+ data_lines.append("# Void category! #0:{}:".format(cat[1]))
+ # ...and all matching language entries!
+ for uid_num, label, uid, flag in langs_cat:
+ if flag == OK:
+ data_lines.append("{}:{}:{}".format(uid_num, label, uid))
+ else:
+ # Non-existing, commented entry!
+ data_lines.append("# {} #{}:{}:{}".format(FLAG_MESSAGES[flag], uid_num, label, uid))
+ with open(os.path.join(settings.TRUNK_MO_DIR, settings.LANGUAGES_FILE), 'w') as f:
+ f.write("\n".join(data_lines))
diff --git a/release/scripts/modules/bl_i18n_utils/rtl_preprocess.py b/release/scripts/modules/bl_i18n_utils/rtl_utils.py
index d28f87cf042..0544f93a262 100755
--- a/release/scripts/modules/bl_i18n_utils/rtl_preprocess.py
+++ b/release/scripts/modules/bl_i18n_utils/rtl_utils.py
@@ -36,18 +36,6 @@ import sys
import ctypes
import re
-try:
- import settings
- import utils
-except:
- from . import (settings, utils)
-
-
-FRIBIDI_LIB = settings.FRIBIDI_LIB
-
-###### Import C library and recreate "defines". #####
-fbd = ctypes.CDLL(FRIBIDI_LIB)
-
#define FRIBIDI_MASK_NEUTRAL 0x00000040L /* Is neutral */
FRIBIDI_PAR_ON = 0x00000040
@@ -80,12 +68,9 @@ FRIBIDI_FLAG_REMOVE_SPECIALS = 0x00040000
FRIBIDI_FLAG_SHAPE_ARAB_PRES = 0x00000100
FRIBIDI_FLAG_SHAPE_ARAB_LIGA = 0x00000200
-FRIBIDI_FLAGS_DEFAULT = FRIBIDI_FLAG_SHAPE_MIRRORING | \
- FRIBIDI_FLAG_REORDER_NSM | \
- FRIBIDI_FLAG_REMOVE_SPECIALS
+FRIBIDI_FLAGS_DEFAULT = FRIBIDI_FLAG_SHAPE_MIRRORING | FRIBIDI_FLAG_REORDER_NSM | FRIBIDI_FLAG_REMOVE_SPECIALS
-FRIBIDI_FLAGS_ARABIC = FRIBIDI_FLAG_SHAPE_ARAB_PRES | \
- FRIBIDI_FLAG_SHAPE_ARAB_LIGA
+FRIBIDI_FLAGS_ARABIC = FRIBIDI_FLAG_SHAPE_ARAB_PRES | FRIBIDI_FLAG_SHAPE_ARAB_LIGA
MENU_DETECT_REGEX = re.compile("%x\\d+\\|")
@@ -158,11 +143,13 @@ def protect_format_seq(msg):
return "".join(ret)
-def log2vis(msgs):
+def log2vis(msgs, settings):
"""
Globally mimics deprecated fribidi_log2vis.
msgs should be an iterable of messages to rtl-process.
"""
+ fbd = ctypes.CDLL(settings.FRIBIDI_LIB)
+
for msg in msgs:
msg = protect_format_seq(msg)
@@ -206,52 +193,3 @@ def log2vis(msgs):
# print(*(ord(c) for c in fbc_str))
yield fbc_str.value
-
-
-##### Command line stuff. #####
-def main():
- import argparse
- parser = argparse.ArgumentParser(description="" \
- "Preprocesses right-to-left languages.\n" \
- "You can use it either standalone, or through " \
- "import_po_from_branches or update_trunk.\n\n" \
- "Note: This has been tested on Linux, not 100% it will " \
- "work nicely on Windows or OsX.\n" \
- "Note: This uses ctypes, as there is no py3 binding for " \
- "fribidi currently. This implies you only need the " \
- "compiled C library to run it.\n" \
- "Note: It handles some formating/escape codes (like " \
- "\\\", %s, %x12, %.4f, etc.), protecting them from ugly " \
- "(evil) fribidi, which seems completely unaware of such " \
- "things (as unicode is...).")
- parser.add_argument('dst', metavar='dst.po',
- help="The dest po into which write the " \
- "pre-processed messages.")
- parser.add_argument('src', metavar='src.po',
- help="The po's to pre-process messages.")
- args = parser.parse_args()
-
- msgs, state, u1 = utils.parse_messages(args.src)
- if state["is_broken"]:
- print("Source po is BROKEN, aborting.")
- return 1
-
- keys = []
- trans = []
- for key, val in msgs.items():
- keys.append(key)
- trans.append("".join(val["msgstr_lines"]))
- trans = log2vis(trans)
- for key, trn in zip(keys, trans):
- # Mono-line for now...
- msgs[key]["msgstr_lines"] = [trn]
-
- utils.write_messages(args.dst, msgs, state["comm_msg"], state["fuzzy_msg"])
-
- print("RTL pre-process completed.")
- return 0
-
-
-if __name__ == "__main__":
- print("\n\n *** Running {} *** \n".format(__file__))
- sys.exit(main())
diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py
index 7e37dffbf10..b94f49b74a2 100644
--- a/release/scripts/modules/bl_i18n_utils/settings.py
+++ b/release/scripts/modules/bl_i18n_utils/settings.py
@@ -24,8 +24,12 @@
# XXX This is a template, most values should be OK, but some you’ll have to
# edit (most probably, BLENDER_EXEC and SOURCE_DIR).
-import os.path
+import json
+import os
+import sys
+
+import bpy
###############################################################################
# MISC
@@ -86,15 +90,24 @@ LANGUAGES = (
(40, "Hindi (मानक हिन्दी)", "hi_IN"),
)
+# Default context, in py!
+DEFAULT_CONTEXT = bpy.app.translations.contexts.default
+
# Name of language file used by Blender to generate translations' menu.
LANGUAGES_FILE = "languages"
-# The min level of completeness for a po file to be imported from /branches
-# into /trunk, as a percentage. -1 means "import everything".
-IMPORT_MIN_LEVEL = -1
+# The min level of completeness for a po file to be imported from /branches into /trunk, as a percentage.
+IMPORT_MIN_LEVEL = 0.0
# Languages in /branches we do not want to import in /trunk currently...
-IMPORT_LANGUAGES_SKIP = {'am', 'bg', 'fi', 'el', 'et', 'ne', 'pl', 'ro', 'uz', 'uz@cyrillic'}
+IMPORT_LANGUAGES_SKIP = {
+ 'am_ET', 'bg_BG', 'fi_FI', 'el_GR', 'et_EE', 'ne_NP', 'pl_PL', 'ro_RO', 'uz_UZ', 'uz_UZ@cyrillic',
+}
+
+# Languages that need RTL pre-processing.
+IMPORT_LANGUAGES_RTL = {
+ 'ar_EG', 'fa_IR', 'he_IL',
+}
# The comment prefix used in generated messages.txt file.
MSG_COMMENT_PREFIX = "#~ "
@@ -111,6 +124,9 @@ PO_COMMENT_PREFIX_SOURCE = "#: "
# The comment prefix used to mark sources of msgids, in po's.
PO_COMMENT_PREFIX_SOURCE_CUSTOM = "#. :src: "
+# The general "generated" comment prefix, in po's.
+PO_COMMENT_PREFIX_GENERATED = "#. "
+
# The comment prefix used to comment entries in po's.
PO_COMMENT_PREFIX_MSG= "#~ "
@@ -127,16 +143,16 @@ PO_MSGID = "msgid "
PO_MSGSTR = "msgstr "
# The 'header' key of po files.
-PO_HEADER_KEY = ("", "")
+PO_HEADER_KEY = (DEFAULT_CONTEXT, "")
PO_HEADER_MSGSTR = (
- "Project-Id-Version: Blender {blender_ver} (r{blender_rev})\\n\n"
+ "Project-Id-Version: {blender_ver} (r{blender_rev})\\n\n"
"Report-Msgid-Bugs-To: \\n\n"
"POT-Creation-Date: {time}\\n\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\n"
"Language-Team: LANGUAGE <LL@li.org>\\n\n"
- "Language: {iso}\\n\n"
+ "Language: {uid}\\n\n"
"MIME-Version: 1.0\\n\n"
"Content-Type: text/plain; charset=UTF-8\\n\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -154,8 +170,8 @@ PO_HEADER_COMMENT = (
TEMPLATE_ISO_ID = "__TEMPLATE__"
-# Default context.
-CONTEXT_DEFAULT = ""
+# Num buttons report their label with a trailing ': '...
+NUM_BUTTON_SUFFIX = ": "
# Undocumented operator placeholder string.
UNDOC_OPS_STR = "(undocumented operator)"
@@ -241,90 +257,123 @@ PYGETTEXT_KEYWORDS = (() +
for it in ("BLF_I18N_MSGID_MULTI_CTXT",))
)
-ESCAPE_RE = (
- (r'((?<!\\)"|(?<!\\)\\(?!\\|"))', r"\\\1"),
- ('\t', r"\\t"),
-)
-
# Should po parser warn when finding a first letter not capitalized?
WARN_MSGID_NOT_CAPITALIZED = True
# Strings that should not raise above warning!
WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
- "", # Simplifies things... :p
- "sin(x) / x",
- "fBM",
- "sqrt(x*x+y*y+z*z)",
- "iTaSC",
+ "", # Simplifies things... :p
+ "ac3",
+ "along X",
+ "along Y",
+ "along Z",
+ "along %s X",
+ "along %s Y",
+ "along %s Z",
+ "along local Z",
+ "ascii",
+ "author", # Addons' field. :/
"bItasc",
- "px",
- "mm",
+ "description", # Addons' field. :/
+ "dx",
+ "fBM",
+ "flac",
+ "fps: %.2f",
+ "fps: %i",
"fStop",
- "sRGB",
+ "gimbal",
+ "global",
+ "iScale",
"iso-8859-15",
- "utf-8",
- "ascii",
- "re",
- "y",
- "ac3",
- "flac",
+ "iTaSC",
+ "iTaSC parameters",
+ "kb",
+ "local",
+ "location", # Addons' field. :/
+ "locking %s X",
+ "locking %s Y",
+ "locking %s Z",
"mkv",
+ "mm",
"mp2",
"mp3",
+ "normal",
"ogg",
- "wav",
- "iTaSC parameters",
- "vBVH",
- "rv",
- "et_EE",
- "eo",
- "available with", # Is part of multi-line msg.
- "virtual parents", # Is part of multi-line msg.
- "description", # Addons' field. :/
- "location", # Addons' field. :/
- "author", # Addons' field. :/
- "in memory to enable editing!", # Is part of multi-line msg.
- "iScale",
- "dx",
"p0",
+ "px",
+ "re",
"res",
+ "rv",
+ "sin(x) / x",
+ "sqrt(x*x+y*y+z*z)",
+ "sRGB",
+ "utf-8",
+ "vBVH",
+ "view",
+ "wav",
+ "y",
+ # Sub-strings.
+ "available with",
+ "can't save image while rendering",
+ "expected a timeline/animation area to be active",
+ "expected a view3d region",
+ "expected a view3d region & editcurve",
+ "expected a view3d region & editmesh",
+ "image file not found",
+ "image path can't be written to",
+ "in memory to enable editing!",
+ "unable to load movie clip",
+ "unable to load text",
+ "unable to open the file",
+ "unknown error reading file",
+ "unknown error stating file",
+ "unknown error writing file",
+ "unsupported font format",
+ "unsupported format",
+ "unsupported image format",
+ "unsupported movie clip format",
+ "verts only",
+ "virtual parents",
}
WARN_MSGID_NOT_CAPITALIZED_ALLOWED |= set(lng[2] for lng in LANGUAGES)
+WARN_MSGID_END_POINT_ALLOWED = {
+ "Numpad .",
+ "Circle|Alt .",
+ "Temp. Diff.",
+ "Float Neg. Exp.",
+ " RNA Path: bpy.types.",
+}
+
PARSER_CACHE_HASH = 'sha1'
+PARSER_TEMPLATE_ID = "__POT__"
+PARSER_PY_ID = "__PY__"
+
+PARSER_PY_MARKER_BEGIN = "\n# ##### BEGIN AUTOGENERATED I18N SECTION #####\n"
+PARSER_PY_MARKER_END = "\n# ##### END AUTOGENERATED I18N SECTION #####\n"
+
+PARSER_MAX_FILE_SIZE = 2**24 # in bytes, i.e. 16 Mb.
###############################################################################
# PATHS
###############################################################################
-# The tools path, should be OK.
-TOOLS_DIR = os.path.join(os.path.dirname(__file__))
-
# The Python3 executable.You’ll likely have to edit it in your user_settings.py
# if you’re under Windows.
PYTHON3_EXEC = "python3"
# The Blender executable!
-# This is just an example, you’ll most likely have to edit it in your user_settings.py!
-BLENDER_EXEC = os.path.abspath(os.path.join(TOOLS_DIR, "..", "..", "..", "..", "blender"))
+# This is just an example, you’ll have to edit it in your user_settings.py!
+BLENDER_EXEC = os.path.abspath(os.path.join("foo", "bar", "blender"))
# check for blender.bin
if not os.path.exists(BLENDER_EXEC):
if os.path.exists(BLENDER_EXEC + ".bin"):
BLENDER_EXEC = BLENDER_EXEC + ".bin"
-# The xgettext tool. You’ll likely have to edit it in your user_settings.py if you’re under Windows.
-GETTEXT_XGETTEXT_EXECUTABLE = "xgettext"
-
-# The gettext msgmerge tool. You’ll likely have to edit it in your user_settings.py if you’re under Windows.
-GETTEXT_MSGMERGE_EXECUTABLE = "msgmerge"
-
# The gettext msgfmt "compiler". You’ll likely have to edit it in your user_settings.py if you’re under Windows.
GETTEXT_MSGFMT_EXECUTABLE = "msgfmt"
-# The svn binary... You’ll likely have to edit it in your user_settings.py if you’re under Windows.
-SVN_EXECUTABLE = "svn"
-
# The FriBidi C compiled library (.so under Linux, .dll under windows...).
# You’ll likely have to edit it in your user_settings.py if you’re under Windows., e.g. using the included one:
# FRIBIDI_LIB = os.path.join(TOOLS_DIR, "libfribidi.dll")
@@ -334,53 +383,62 @@ FRIBIDI_LIB = "libfribidi.so.0"
RTL_PREPROCESS_FILE = "is_rtl"
# The Blender source root path.
-# This is just an example, you’ll most likely have to override it in your user_settings.py!
-SOURCE_DIR = os.path.abspath(os.path.join(TOOLS_DIR, "..", "..", "..", "..", "..", "..", "blender_msgs"))
+# This is just an example, you’ll have to override it in your user_settings.py!
+SOURCE_DIR = os.path.abspath(os.path.join("blender"))
+
+# The bf-translation repository (you'll have to override this in your user_settings.py).
+I18N_DIR = os.path.abspath(os.path.join("i18n"))
-# The bf-translation repository (you'll likely have to override this in your user_settings.py).
-I18N_DIR = os.path.abspath(os.path.join(TOOLS_DIR, "..", "..", "..", "..", "..", "..", "i18n"))
+# The /branches path (relative to I18N_DIR).
+REL_BRANCHES_DIR = os.path.join("branches")
-# The /branches path (overriden in bf-translation's i18n_override_settings.py).
-BRANCHES_DIR = os.path.join(I18N_DIR, "branches")
+# The /trunk path (relative to I18N_DIR).
+REL_TRUNK_DIR = os.path.join("trunk")
-# The /trunk path (overriden in bf-translation's i18n_override_settings.py).
-TRUNK_DIR = os.path.join(I18N_DIR, "trunk")
+# The /trunk/po path (relative to I18N_DIR).
+REL_TRUNK_PO_DIR = os.path.join(REL_TRUNK_DIR, "po")
-# The /trunk/po path (overriden in bf-translation's i18n_override_settings.py).
-TRUNK_PO_DIR = os.path.join(TRUNK_DIR, "po")
+# The /trunk/mo path (relative to I18N_DIR).
+REL_TRUNK_MO_DIR = os.path.join(REL_TRUNK_DIR, "locale")
-# The /trunk/mo path (overriden in bf-translation's i18n_override_settings.py).
-TRUNK_MO_DIR = os.path.join(TRUNK_DIR, "locale")
+# The Blender source path to check for i18n macros (relative to SOURCE_DIR).
+REL_POTFILES_SOURCE_DIR = os.path.join("source")
-# The file storing Blender-generated messages.
-FILE_NAME_MESSAGES = os.path.join(TRUNK_PO_DIR, "messages.txt")
+# The template messages file (relative to I18N_DIR).
+REL_FILE_NAME_POT = os.path.join(REL_BRANCHES_DIR, DOMAIN + ".pot")
-# The Blender source path to check for i18n macros.
-POTFILES_SOURCE_DIR = os.path.join(SOURCE_DIR, "source")
+# Mo root datapath.
+REL_MO_PATH_ROOT = os.path.join(REL_TRUNK_DIR, "locale")
-# The "source" file storing which files should be processed by xgettext, used to create FILE_NAME_POTFILES
-FILE_NAME_SRC_POTFILES = os.path.join(TRUNK_PO_DIR, "_POTFILES.in")
+# Mo path generator for a given language.
+REL_MO_PATH_TEMPLATE = os.path.join(REL_MO_PATH_ROOT, "{}", "LC_MESSAGES")
-# The final (generated) file storing which files should be processed by xgettext.
-FILE_NAME_POTFILES = os.path.join(TRUNK_PO_DIR, "POTFILES.in")
+# Mo path generator for a given language (relative to any "locale" dir).
+MO_PATH_ROOT_RELATIVE = os.path.join("locale")
+MO_PATH_TEMPLATE_RELATIVE = os.path.join(MO_PATH_ROOT_RELATIVE, "{}", "LC_MESSAGES")
-# The template messages file.
-FILE_NAME_POT = os.path.join(TRUNK_PO_DIR, ".".join((DOMAIN, "pot")))
+# Mo file name.
+MO_FILE_NAME = DOMAIN + ".mo"
-# Other py files that should be searched for ui strings, relative to SOURCE_DIR.
-# Needed for Cycles, currently...
+# Where to search for py files that may contain ui strings (relative to one of the 'resource_path' of Blender).
CUSTOM_PY_UI_FILES = [
- os.path.join("intern", "cycles", "blender", "addon", "ui.py"),
- os.path.join("release", "scripts", "modules", "rna_prop_ui.py"),
+ os.path.join("scripts", "startup", "bl_ui"),
+ os.path.join("scripts", "modules", "rna_prop_ui.py"),
]
+# An optional text file listing files to force include/exclude from py_xgettext process.
+SRC_POTFILES = ""
# A cache storing validated msgids, to avoid re-spellchecking them.
SPELL_CACHE = os.path.join("/tmp", ".spell_cache")
+# Threshold defining whether a new msgid is similar enough with an old one to reuse its translation...
+SIMILAR_MSGID_THRESHOLD = 0.75
+
+# Additional import paths to add to sys.path (';' separated)...
+INTERN_PY_SYS_PATHS = ""
# Custom override settings must be one dir above i18n tools itself!
-import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
try:
from bl_i18n_override_settings import *
@@ -392,3 +450,104 @@ try:
from user_settings import *
except ImportError: # If no user_settings available, it’s no error!
pass
+
+
+for p in set(INTERN_PY_SYS_PATHS.split(";")):
+ if p:
+ sys.path.append(p)
+
+
+# The settings class itself!
+def _do_get(ref, path):
+ return os.path.normpath(os.path.join(ref, path))
+
+def _do_set(ref, path):
+ path = os.path.normpath(path)
+ # If given path is absolute, make it relative to current ref one (else we consider it is already the case!)
+ if os.path.isabs(path):
+ return os.path.relpath(path, ref)
+ else:
+ return path
+
+def _gen_get_set_path(ref, name):
+ def _get(self):
+ return _do_get(getattr(self, ref), getattr(self, name))
+ def _set(self, value):
+ setattr(self, name, _do_set(getattr(self, ref), value))
+ return _get, _set
+
+def _gen_get_set_paths(ref, name):
+ def _get(self):
+ return [_do_get(getattr(self, ref), p) for p in getattr(self, name)]
+ def _set(self, value):
+ setattr(self, name, [_do_set(getattr(self, ref), p) for p in value])
+ return _get, _set
+
+class I18nSettings:
+ """
+ Class allowing persistence of our settings!
+ Saved in JSon format, so settings should be JSon'able objects!
+ """
+ _settings = None
+
+ def __new__(cls, *args, **kwargs):
+ # Addon preferences are singleton by definition, so is this class!
+ if not I18nSettings._settings:
+ cls._settings = super(I18nSettings, cls).__new__(cls)
+ cls._settings.__dict__ = {uid: data for uid, data in globals().items() if not uid.startswith("_")}
+ return I18nSettings._settings
+
+ def from_json(self, string):
+ data = dict(json.loads(string))
+ # Special case... :/
+ if "INTERN_PY_SYS_PATHS" in data:
+ self.PY_SYS_PATHS = data["INTERN_PY_SYS_PATHS"]
+ self.__dict__.update(data)
+
+ def to_json(self):
+ # Only save the diff from default i18n_settings!
+ glob = globals()
+ export_dict = {uid: val for uid, val in self.__dict__.items() if glob.get(uid) != val}
+ return json.dumps(export_dict)
+
+ def load(self, fname, reset=False):
+ if reset:
+ self.__dict__ = {uid: data for uid, data in globals().items() if not uid.startswith("_")}
+ if isinstance(fname, str):
+ if not os.path.isfile(fname):
+ return
+ with open(fname) as f:
+ self.from_json(f.read())
+ # Else assume fname is already a file(like) object!
+ else:
+ self.from_json(fname.read())
+
+ def save(self, fname):
+ if isinstance(fname, str):
+ with open(fname, 'w') as f:
+ f.write(self.to_json())
+ # Else assume fname is already a file(like) object!
+ else:
+ fname.write(self.to_json())
+
+ BRANCHES_DIR = property(*(_gen_get_set_path("I18N_DIR", "REL_BRANCHES_DIR")))
+ TRUNK_DIR = property(*(_gen_get_set_path("I18N_DIR", "REL_TRUNK_DIR")))
+ TRUNK_PO_DIR = property(*(_gen_get_set_path("I18N_DIR", "REL_TRUNK_PO_DIR")))
+ TRUNK_MO_DIR = property(*(_gen_get_set_path("I18N_DIR", "REL_TRUNK_MO_DIR")))
+ POTFILES_SOURCE_DIR = property(*(_gen_get_set_path("SOURCE_DIR", "REL_POTFILES_SOURCE_DIR")))
+ FILE_NAME_POT = property(*(_gen_get_set_path("I18N_DIR", "REL_FILE_NAME_POT")))
+ MO_PATH_ROOT = property(*(_gen_get_set_path("I18N_DIR", "REL_MO_PATH_ROOT")))
+ MO_PATH_TEMPLATE = property(*(_gen_get_set_path("I18N_DIR", "REL_MO_PATH_TEMPLATE")))
+
+ def _get_py_sys_paths(self):
+ return self.INTERN_PY_SYS_PATHS
+ def _set_py_sys_paths(self, val):
+ old_paths = set(self.INTERN_PY_SYS_PATHS.split(";")) - {""}
+ new_paths = set(val.split(";")) - {""}
+ for p in old_paths - new_paths:
+ if p in sys.path:
+ sys.path.remove(p)
+ for p in new_paths - old_paths:
+ sys.path.append(p)
+ self.INTERN_PY_SYS_PATHS = val
+ PY_SYS_PATHS = property(_get_py_sys_paths, _set_py_sys_paths)
diff --git a/release/scripts/modules/bl_i18n_utils/spell_check_utils.py b/release/scripts/modules/bl_i18n_utils/spell_check_utils.py
index 6adf3213b56..40cbd6e9d17 100644
--- a/release/scripts/modules/bl_i18n_utils/spell_check_utils.py
+++ b/release/scripts/modules/bl_i18n_utils/spell_check_utils.py
@@ -18,518 +18,572 @@
# <pep8 compliant>
+import enchant
+import os
+import pickle
import re
-_valid_before = "(?<=[\\s*'\"`])|(?<=[a-zA-Z][/-])|(?<=^)"
-_valid_after = "(?=[\\s'\"`.!?,;:])|(?=[/-]\\s*[a-zA-Z])|(?=$)"
-_valid_words = "(?:{})(?:(?:[A-Z]+[a-z]*)|[A-Z]*|[a-z]*)(?:{})".format(_valid_before, _valid_after)
-_reg = re.compile(_valid_words)
+class SpellChecker():
+ """
+ A basic spell checker.
+ """
+ # These must be all lower case for comparisons
+ uimsgs = {
+ # OK words
+ "aren", # aren't
+ "betweens", # yuck! in-betweens!
+ "boolean", "booleans",
+ "couldn", # couldn't
+ "decrement",
+ "derivate",
+ "doesn", # doesn't
+ "fader",
+ "hasn", # hasn't
+ "hoc", # ad-hoc
+ "indices",
+ "iridas",
+ "isn", # isn't
+ "iterable",
+ "kyrgyz",
+ "latin",
+ "merchantability",
+ "mplayer",
+ "vertices",
-def split_words(text):
- return [w for w in _reg.findall(text) if w]
+ # Merged words
+ "addon", "addons",
+ "antialiasing",
+ "arcsine", "arccosine", "arctangent",
+ "autoclip",
+ "autocomplete",
+ "autoname",
+ "autosave",
+ "autoscale",
+ "autosmooth",
+ "autosplit",
+ "backface", "backfacing",
+ "backimage",
+ "backscattered",
+ "bandnoise",
+ "bindcode",
+ "bitrate",
+ "blendin",
+ "bonesize",
+ "boundbox",
+ "boxpack",
+ "buffersize",
+ "builtin", "builtins",
+ "bytecode",
+ "chunksize",
+ "de",
+ "defocus",
+ "denoise",
+ "despill", "despilling",
+ "editcurve",
+ "editmesh",
+ "filebrowser",
+ "filelist",
+ "filename", "filenames",
+ "filepath", "filepaths",
+ "forcefield", "forcefields",
+ "fulldome", "fulldomes",
+ "fullscreen",
+ "gridline",
+ "hemi",
+ "inbetween",
+ "inscatter", "inscattering",
+ "libdata",
+ "lightless",
+ "lookup", "lookups",
+ "mathutils",
+ "midlevel",
+ "midground",
+ "mixdown",
+ "multi",
+ "multifractal",
+ "multires", "multiresolution",
+ "multisampling",
+ "multitexture",
+ "multiuser",
+ "namespace",
+ "keyconfig",
+ "playhead",
+ "polyline",
+ "popup", "popups",
+ "pre",
+ "precalculate",
+ "prefetch",
+ "premultiply", "premultiplied",
+ "prepass",
+ "prepend",
+ "preprocess", "preprocessing",
+ "preseek",
+ "readonly",
+ "realtime",
+ "rekey",
+ "remesh",
+ "reprojection",
+ "resize",
+ "restpose",
+ "retarget", "retargets", "retargeting", "retargeted",
+ "ringnoise",
+ "rolloff",
+ "screencast", "screenshot", "screenshots",
+ "selfcollision",
+ "singletexture",
+ "spellcheck", "spellchecking",
+ "startup",
+ "stateful",
+ "starfield",
+ "subflare", "subflares",
+ "subframe", "subframes",
+ "subclass", "subclasses", "subclassing",
+ "subdirectory", "subdirectories", "subdir", "subdirs",
+ "submodule", "submodules",
+ "subpath",
+ "subsize",
+ "substep", "substeps",
+ "targetless",
+ "textbox", "textboxes",
+ "tilemode",
+ "timestamp", "timestamps",
+ "timestep", "timesteps",
+ "todo",
+ "un",
+ "unbake",
+ "uncomment",
+ "undeformed",
+ "undistort", "undistortion",
+ "ungroup",
+ "unhide",
+ "unindent",
+ "unkeyed",
+ "unpremultiply",
+ "unprojected",
+ "unreacted",
+ "unregister",
+ "unselected",
+ "unsubdivided", "unsubdivide",
+ "unshadowed",
+ "unspill",
+ "unstitchable",
+ "vectorscope",
+ "whitespace", "whitespaces",
+ "worldspace",
+ "workflow",
+ # Neologisms, slangs
+ "affectable",
+ "automagic", "automagically",
+ "blobby",
+ "blockiness", "blocky",
+ "collider", "colliders",
+ "deformer", "deformers",
+ "determinator",
+ "editability",
+ "keyer",
+ "lacunarity",
+ "numerics",
+ "occluder",
+ "passepartout",
+ "perspectively",
+ "pixelate",
+ "polygonization",
+ "selectability",
+ "slurph",
+ "stitchable",
+ "symmetrize",
+ "trackability",
+ "transmissivity",
+ "rasterized", "rasterization", "rasterizer",
+ "renderer", "renderable", "renderability",
-# These must be all lower case for comparisons
-dict_uimsgs = {
- # OK words
- "aren", # aren't
- "betweens", # yuck! in-betweens!
- "boolean", "booleans",
- "couldn", # couldn't
- "decrement",
- "derivate",
- "doesn", # doesn't
- "fader",
- "hasn", # hasn't
- "hoc", # ad-hoc
- "indices",
- "iridas",
- "isn", # isn't
- "iterable",
- "kyrgyz",
- "latin",
- "merchantability",
- "mplayer",
- "vertices",
+ # Abbreviations
+ "aero",
+ "amb",
+ "anim",
+ "bool",
+ "calc",
+ "config", "configs",
+ "const",
+ "coord", "coords",
+ "degr",
+ "dof",
+ "dupli", "duplis",
+ "eg",
+ "esc",
+ "expr",
+ "fac",
+ "fra",
+ "frs",
+ "grless",
+ "http",
+ "init",
+ "kbit", "kb",
+ "lang", "langs",
+ "lclick", "rclick",
+ "lensdist",
+ "loc", "rot", "pos",
+ "lorem",
+ "luma",
+ "mem",
+ "multicam",
+ "num",
+ "ok",
+ "orco",
+ "ortho",
+ "persp",
+ "pref", "prefs",
+ "prev",
+ "param",
+ "premul",
+ "quad", "quads",
+ "quat", "quats",
+ "recalc", "recalcs",
+ "refl",
+ "sel",
+ "spec",
+ "struct", "structs",
+ "sys",
+ "tex",
+ "tri", "tris",
+ "uv", "uvs", "uvw", "uw", "uvmap",
+ "vec",
+ "vel", # velocity!
+ "vert", "verts",
+ "vis",
+ "xyz", "xzy", "yxz", "yzx", "zxy", "zyx",
+ "xy", "xz", "yx", "yz", "zx", "zy",
- # Merged words
- "addon", "addons",
- "antialiasing",
- "arcsine", "arccosine", "arctangent",
- "autoclip",
- "autocomplete",
- "autoname",
- "autosave",
- "autoscale",
- "autosmooth",
- "autosplit",
- "backface", "backfacing",
- "backimage",
- "backscattered",
- "bandnoise",
- "bindcode",
- "bitrate",
- "blendin",
- "bonesize",
- "boundbox",
- "boxpack",
- "buffersize",
- "builtin", "builtins",
- "bytecode",
- "chunksize",
- "de",
- "defocus",
- "denoise",
- "despill", "despilling",
- "filebrowser",
- "filelist",
- "filename", "filenames",
- "filepath", "filepaths",
- "forcefield", "forcefields",
- "fulldome", "fulldomes",
- "fullscreen",
- "gridline",
- "hemi",
- "inbetween",
- "inscatter", "inscattering",
- "libdata",
- "lightless",
- "lookup", "lookups",
- "mathutils",
- "midlevel",
- "midground",
- "mixdown",
- "multi",
- "multifractal",
- "multires", "multiresolution",
- "multisampling",
- "multitexture",
- "multiuser",
- "namespace",
- "keyconfig",
- "playhead",
- "polyline",
- "popup", "popups",
- "pre",
- "precalculate",
- "prefetch",
- "premultiply", "premultiplied",
- "prepass",
- "prepend",
- "preprocess", "preprocessing",
- "preseek",
- "readonly",
- "realtime",
- "rekey",
- "remesh",
- "reprojection",
- "resize",
- "restpose",
- "retarget", "retargets", "retargeting", "retargeted",
- "ringnoise",
- "rolloff",
- "screencast", "screenshot", "screenshots",
- "selfcollision",
- "singletexture",
- "startup",
- "stateful",
- "starfield",
- "subflare", "subflares",
- "subframe", "subframes",
- "subclass", "subclasses", "subclassing",
- "subdirectory", "subdirectories", "subdir", "subdirs",
- "submodule", "submodules",
- "subpath",
- "subsize",
- "substep", "substeps",
- "targetless",
- "textbox", "textboxes",
- "tilemode",
- "timestamp", "timestamps",
- "timestep", "timesteps",
- "todo",
- "un",
- "unbake",
- "uncomment",
- "undeformed",
- "undistort", "undistortion",
- "ungroup",
- "unhide",
- "unindent",
- "unkeyed",
- "unpremultiply",
- "unprojected",
- "unreacted",
- "unregister",
- "unselected",
- "unsubdivided", "unsubdivide",
- "unshadowed",
- "unspill",
- "unstitchable",
- "vectorscope",
- "whitespace", "whitespaces",
- "worldspace",
- "workflow",
+ # General computer/science terms
+ "boid", "boids",
+ "equisolid",
+ "euler", "eulers",
+ "fribidi",
+ "gettext",
+ "hashable",
+ "intrinsics",
+ "isosurface",
+ "jitter", "jittering", "jittered",
+ "keymap", "keymaps",
+ "lambertian",
+ "laplacian",
+ "metadata",
+ "msgfmt",
+ "nand", "xnor",
+ "normals",
+ "numpad",
+ "octree",
+ "opengl",
+ "pulldown", "pulldowns",
+ "quantized",
+ "samplerate",
+ "scrollback",
+ "scrollbar",
+ "scroller",
+ "searchable",
+ "spacebar",
+ "tooltip", "tooltips",
+ "trackpad",
+ "unicode",
+ "viewport", "viewports",
+ "viscoelastic",
+ "wildcard", "wildcards",
- # Neologisms, slangs
- "affectable",
- "automagic", "automagically",
- "blobby",
- "blockiness", "blocky",
- "collider", "colliders",
- "deformer", "deformers",
- "determinator",
- "editability",
- "keyer",
- "lacunarity",
- "numerics",
- "occluder",
- "passepartout",
- "perspectively",
- "pixelate",
- "polygonization",
- "selectability",
- "slurph",
- "stitchable",
- "symmetrize",
- "trackability",
- "transmissivity",
- "rasterized", "rasterization", "rasterizer",
- "renderer", "renderable", "renderability",
+ # General computer graphics terms
+ "anaglyph",
+ "bezier", "beziers",
+ "bicubic",
+ "bilinear",
+ "blackpoint", "whitepoint",
+ "blinn",
+ "bokeh",
+ "catadioptric",
+ "centroid",
+ "chrominance",
+ "codec", "codecs",
+ "collada",
+ "compositing",
+ "crossfade",
+ "deinterlace",
+ "dropoff",
+ "dv",
+ "eigenvectors",
+ "equirectangular",
+ "fisheye",
+ "framerate",
+ "gimbal",
+ "grayscale",
+ "icosphere",
+ "inpaint",
+ "lightmap",
+ "lossless", "lossy",
+ "matcap",
+ "midtones",
+ "mipmap", "mipmaps", "mip",
+ "ngon", "ngons",
+ "ntsc",
+ "nurb", "nurbs",
+ "perlin",
+ "phong",
+ "radiosity",
+ "raytrace", "raytracing", "raytraced",
+ "renderfarm",
+ "shader", "shaders",
+ "specular", "specularity",
+ "spillmap",
+ "sobel",
+ "tonemap",
+ "toon",
+ "timecode",
+ "voronoi",
+ "voxel", "voxels",
+ "wireframe",
+ "zmask",
+ "ztransp",
- # Abbreviations
- "aero",
- "amb",
- "anim",
- "bool",
- "calc",
- "config", "configs",
- "const",
- "coord", "coords",
- "degr",
- "dof",
- "dupli", "duplis",
- "eg",
- "esc",
- "expr",
- "fac",
- "fra",
- "frs",
- "grless",
- "http",
- "init",
- "kbit", "kb",
- "lensdist",
- "loc", "rot", "pos",
- "lorem",
- "luma",
- "mem",
- "multicam",
- "num",
- "ok",
- "orco",
- "ortho",
- "persp",
- "pref", "prefs",
- "prev",
- "param",
- "premul",
- "quad", "quads",
- "quat", "quats",
- "recalc", "recalcs",
- "refl",
- "sel",
- "spec",
- "struct", "structs",
- "tex",
- "tri", "tris",
- "uv", "uvs", "uvw", "uw", "uvmap",
- "vec",
- "vel", # velocity!
- "vert", "verts",
- "vis",
- "xyz", "xzy", "yxz", "yzx", "zxy", "zyx",
- "xy", "xz", "yx", "yz", "zx", "zy",
+ # Blender terms
+ "audaspace",
+ "bbone",
+ "breakdowner",
+ "bspline",
+ "bweight",
+ "colorband",
+ "datablock", "datablocks",
+ "despeckle",
+ "dopesheet",
+ "dupliface", "duplifaces",
+ "dupliframe", "dupliframes",
+ "dupliobject", "dupliob",
+ "dupligroup",
+ "duplivert",
+ "editbone",
+ "editmode",
+ "fcurve", "fcurves",
+ "fluidsim",
+ "frameserver",
+ "enum",
+ "keyframe", "keyframes", "keyframing", "keyframed",
+ "metaball", "metaballs",
+ "metaelement", "metaelements",
+ "metastrip", "metastrips",
+ "movieclip",
+ "mpoly",
+ "mtex",
+ "nabla",
+ "navmesh",
+ "outliner",
+ "paintmap", "paintmaps",
+ "polygroup", "polygroups",
+ "poselib",
+ "pushpull",
+ "pyconstraint", "pyconstraints",
+ "shapekey", "shapekeys",
+ "shrinkfatten",
+ "shrinkwrap",
+ "softbody",
+ "stucci",
+ "sunsky",
+ "subsurf",
+ "tessface", "tessfaces",
+ "texface",
+ "timeline", "timelines",
+ "tosphere",
+ "uilist",
+ "vcol", "vcols",
+ "vgroup", "vgroups",
+ "vinterlace",
+ "wetmap", "wetmaps",
+ "wpaint",
+ "uvwarp",
- # General computer/science terms
- "boid", "boids",
- "equisolid",
- "euler", "eulers",
- "hashable",
- "intrinsics",
- "isosurface",
- "jitter", "jittering", "jittered",
- "keymap", "keymaps",
- "lambertian",
- "laplacian",
- "metadata",
- "nand", "xnor",
- "normals",
- "numpad",
- "octree",
- "opengl",
- "pulldown", "pulldowns",
- "quantized",
- "samplerate",
- "scrollback",
- "scrollbar",
- "scroller",
- "searchable",
- "spacebar",
- "tooltip", "tooltips",
- "trackpad",
- "unicode",
- "viewport", "viewports",
- "viscoelastic",
- "wildcard", "wildcards",
+ # Algorithm names
+ "beckmann",
+ "catmull",
+ "catrom",
+ "chebychev",
+ "courant",
+ "kutta",
+ "lennard",
+ "minkowski",
+ "minnaert",
+ "musgrave",
+ "nayar",
+ "netravali",
+ "oren",
+ "prewitt",
+ "runge",
+ "verlet",
+ "worley",
- # General computer graphics terms
- "anaglyph",
- "bezier", "beziers",
- "bicubic",
- "bilinear",
- "blackpoint", "whitepoint",
- "blinn",
- "bokeh",
- "catadioptric",
- "centroid",
- "chrominance",
- "codec", "codecs",
- "collada",
- "compositing",
- "crossfade",
- "deinterlace",
- "dropoff",
- "dv",
- "eigenvectors",
- "equirectangular",
- "fisheye",
- "framerate",
- "gimbal",
- "grayscale",
- "icosphere",
- "inpaint",
- "lightmap",
- "lossless", "lossy",
- "matcap",
- "midtones",
- "mipmap", "mipmaps", "mip",
- "ngon", "ngons",
- "ntsc",
- "nurb", "nurbs",
- "perlin",
- "phong",
- "radiosity",
- "raytrace", "raytracing", "raytraced",
- "renderfarm",
- "shader", "shaders",
- "specular", "specularity",
- "spillmap",
- "sobel",
- "tonemap",
- "toon",
- "timecode",
- "voronoi",
- "voxel", "voxels",
- "wireframe",
- "zmask",
- "ztransp",
+ # Acronyms
+ "aa", "msaa",
+ "ao",
+ "api",
+ "asc", "cdl",
+ "ascii",
+ "atrac",
+ "bsdf",
+ "bw",
+ "ccd",
+ "cmd",
+ "cpus",
+ "ctrl",
+ "cw", "ccw",
+ "dev",
+ "djv",
+ "dpi",
+ "dvar",
+ "dx",
+ "eo",
+ "fh",
+ "fov",
+ "fft",
+ "futura",
+ "gfx",
+ "gl",
+ "glsl",
+ "gpl",
+ "gpu", "gpus",
+ "hc",
+ "hdc",
+ "hdr",
+ "hh", "mm", "ss", "ff", # hh:mm:ss:ff timecode
+ "hsv", "hsva",
+ "id",
+ "ior",
+ "itu",
+ "lhs",
+ "lmb", "mmb", "rmb",
+ "kb",
+ "mocap",
+ "msgid", "msgids",
+ "mux",
+ "ndof",
+ "ppc",
+ "precisa",
+ "px",
+ "qmc",
+ "rgb", "rgba",
+ "rhs",
+ "rv",
+ "sdl",
+ "sl",
+ "smpte",
+ "svn",
+ "ui",
+ "unix",
+ "vbo", "vbos",
+ "ycc", "ycca",
+ "yuv", "yuva",
- # Blender terms
- "audaspace",
- "bbone",
- "breakdowner",
- "bspline",
- "bweight",
- "colorband",
- "datablock", "datablocks",
- "despeckle",
- "dopesheet",
- "dupliface", "duplifaces",
- "dupliframe", "dupliframes",
- "dupliobject", "dupliob",
- "dupligroup",
- "duplivert",
- "editbone",
- "editmode",
- "fcurve", "fcurves",
- "fluidsim",
- "frameserver",
- "enum",
- "keyframe", "keyframes", "keyframing", "keyframed",
- "metaball", "metaballs",
- "metaelement", "metaelements",
- "metastrip", "metastrips",
- "movieclip",
- "mpoly",
- "mtex",
- "nabla",
- "navmesh",
- "outliner",
- "paintmap", "paintmaps",
- "polygroup", "polygroups",
- "poselib",
- "pushpull",
- "pyconstraint", "pyconstraints",
- "shapekey", "shapekeys",
- "shrinkfatten",
- "shrinkwrap",
- "softbody",
- "stucci",
- "sunsky",
- "subsurf",
- "tessface", "tessfaces",
- "texface",
- "timeline", "timelines",
- "tosphere",
- "uilist",
- "vcol", "vcols",
- "vgroup", "vgroups",
- "vinterlace",
- "wetmap", "wetmaps",
- "wpaint",
- "uvwarp",
+ # Blender acronyms
+ "bge",
+ "bli",
+ "bpy",
+ "bvh",
+ "dbvt",
+ "dop", # BLI K-Dop BVH
+ "ik",
+ "nla",
+ "py",
+ "qbvh",
+ "rna",
+ "rvo",
+ "simd",
+ "sph",
+ "svbvh",
- # Algorithm names
- "beckmann",
- "catmull",
- "catrom",
- "chebychev",
- "courant",
- "kutta",
- "lennard",
- "minkowski",
- "minnaert",
- "musgrave",
- "nayar",
- "netravali",
- "oren",
- "prewitt",
- "runge",
- "verlet",
- "worley",
+ # Files types/formats
+ "avi",
+ "attrac",
+ "autocad",
+ "autodesk",
+ "bmp",
+ "btx",
+ "cineon",
+ "dpx",
+ "dxf",
+ "eps",
+ "exr",
+ "fbx",
+ "ffmpeg",
+ "flac",
+ "gzip",
+ "ico",
+ "jpg", "jpeg",
+ "json",
+ "matroska",
+ "mdd",
+ "mkv",
+ "mpeg", "mjpeg",
+ "mtl",
+ "ogg",
+ "openjpeg",
+ "osl",
+ "oso",
+ "piz",
+ "png",
+ "po",
+ "quicktime",
+ "rle",
+ "sgi",
+ "stl",
+ "svg",
+ "targa", "tga",
+ "tiff",
+ "theora",
+ "vorbis",
+ "wav",
+ "xiph",
+ "xml",
+ "xna",
+ "xvid",
+ }
- # Acronyms
- "aa", "msaa",
- "api",
- "asc", "cdl",
- "ascii",
- "atrac",
- "bw",
- "ccd",
- "cmd",
- "cpus",
- "ctrl",
- "cw", "ccw",
- "dev",
- "djv",
- "dpi",
- "dvar",
- "dx",
- "eo",
- "fh",
- "fov",
- "fft",
- "futura",
- "gfx",
- "gl",
- "glsl",
- "gpl",
- "gpu", "gpus",
- "hc",
- "hdc",
- "hdr",
- "hh", "mm", "ss", "ff", # hh:mm:ss:ff timecode
- "hsv", "hsva",
- "id",
- "itu",
- "lhs",
- "lmb", "mmb", "rmb",
- "mux",
- "ndof",
- "ppc",
- "precisa",
- "px",
- "qmc",
- "rgb", "rgba",
- "rhs",
- "rv",
- "sdl",
- "sl",
- "smpte",
- "svn",
- "ui",
- "unix",
- "vbo", "vbos",
- "ycc", "ycca",
- "yuv", "yuva",
+ _valid_before = "(?<=[\\s*'\"`])|(?<=[a-zA-Z][/-])|(?<=^)"
+ _valid_after = "(?=[\\s'\"`.!?,;:])|(?=[/-]\\s*[a-zA-Z])|(?=$)"
+ _valid_words = "(?:{})(?:(?:[A-Z]+[a-z]*)|[A-Z]*|[a-z]*)(?:{})".format(_valid_before, _valid_after)
+ _split_words = re.compile(_valid_words).findall
- # Blender acronyms
- "bge",
- "bli",
- "bvh",
- "dbvt",
- "dop", # BLI K-Dop BVH
- "ik",
- "nla",
- "py",
- "qbvh",
- "rna",
- "rvo",
- "simd",
- "sph",
- "svbvh",
+ @classmethod
+ def split_words(cls, text):
+ return [w for w in cls._split_words(text) if w]
- # CG acronyms
- "ao",
- "bsdf",
- "ior",
- "mocap",
+ def __init__(self, settings, lang="en_US"):
+ self.settings = settings
+ self.dict_spelling = enchant.Dict(lang)
+ self.cache = set(self.uimsgs)
- # Files types/formats
- "avi",
- "attrac",
- "autocad",
- "autodesk",
- "bmp",
- "btx",
- "cineon",
- "dpx",
- "dxf",
- "eps",
- "exr",
- "fbx",
- "ffmpeg",
- "flac",
- "gzip",
- "ico",
- "jpg", "jpeg",
- "matroska",
- "mdd",
- "mkv",
- "mpeg", "mjpeg",
- "mtl",
- "ogg",
- "openjpeg",
- "osl",
- "oso",
- "piz",
- "png",
- "po",
- "quicktime",
- "rle",
- "sgi",
- "stl",
- "svg",
- "targa", "tga",
- "tiff",
- "theora",
- "vorbis",
- "wav",
- "xiph",
- "xml",
- "xna",
- "xvid",
-}
+ cache = self.settings.SPELL_CACHE
+ if cache and os.path.exists(cache):
+ with open(cache, 'rb') as f:
+ self.cache |= set(pickle.load(f))
+
+ def __del__(self):
+ cache = self.settings.SPELL_CACHE
+ if cache and os.path.exists(cache):
+ with open(cache, 'wb') as f:
+ pickle.dump(self.cache, f)
+
+ def check(self, txt):
+ ret = []
+
+ if txt in self.cache:
+ return ret
+
+ for w in self.split_words(txt):
+ w_lower = w.lower()
+ if w_lower in self.cache:
+ continue
+ if not self.dict_spelling.check(w):
+ ret.append((w, self.dict_spelling.suggest(w)))
+ else:
+ self.cache.add(w_lower)
+
+ if not ret:
+ self.cache.add(txt)
+
+ return ret
diff --git a/release/scripts/modules/bl_i18n_utils/update_languages_menu.py b/release/scripts/modules/bl_i18n_utils/update_languages_menu.py
deleted file mode 100755
index 6263f1c1e64..00000000000
--- a/release/scripts/modules/bl_i18n_utils/update_languages_menu.py
+++ /dev/null
@@ -1,148 +0,0 @@
-#!/usr/bin/python3
-
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public 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>
-
-# Update "languages" text file used by Blender at runtime to build translations menu.
-
-import os
-import sys
-import shutil
-
-try:
- import settings
- import utils
-except:
- from . import (settings, utils)
-
-TRUNK_PO_DIR = settings.TRUNK_PO_DIR
-TRUNK_MO_DIR = settings.TRUNK_MO_DIR
-
-LANGUAGES_CATEGORIES = settings.LANGUAGES_CATEGORIES
-LANGUAGES = settings.LANGUAGES
-LANGUAGES_FILE = settings.LANGUAGES_FILE
-
-OK = 0
-MISSING = 1
-TOOLOW = 2
-FORBIDDEN = 3
-FLAG_MESSAGES = {
- OK: "",
- MISSING: "No translation yet!",
- TOOLOW: "Not enough advanced to be included...",
- FORBIDDEN: "Explicitly forbidden!",
-}
-
-def find_matching_po(languages, stats, forbidden):
- """Match languages defined in LANGUAGES setting to relevant po, if possible!"""
- ret = []
- for uid, label, org_key, in languages:
- key = org_key
- if key not in stats:
- # Try to simplify the key (eg from es_ES to es).
- if '_' in org_key:
- key = org_key[0:org_key.index('_')]
- # For stuff like sr_SR@latin -> sr@latin...
- if '@' in org_key:
- key = key + org_key[org_key.index('@'):]
- if key in stats:
- if key in forbidden:
- ret.append((stats[key], uid, label, org_key, FORBIDDEN))
- else:
- ret.append((stats[key], uid, label, org_key, OK))
- else:
- ret.append((0.0, uid, label, org_key, MISSING))
- return ret
-
-def main():
- import argparse
- parser = argparse.ArgumentParser(description="Update 'languages' text file used by Blender at runtime to build "
- "translations menu.")
- parser.add_argument('-m', '--min_translation', type=int, default=-100,
- help="Minimum level of translation, as a percentage (translations below this are commented out "
- "in menu).")
- parser.add_argument('langs', metavar='ISO_code', nargs='*',
- help="Unconditionally exclude those languages from the menu.")
- args = parser.parse_args()
-
- ret = 0
- min_trans = args.min_translation / 100.0
- forbidden = set(args.langs)
- # 'DEFAULT' and en_US are always valid, fully-translated "languages"!
- stats = {"DEFAULT": 1.0, "en_US": 1.0}
-
- # Get the "done level" of each po in trunk...
- for po in os.listdir(TRUNK_PO_DIR):
- if po.endswith(".po") and not po.endswith("_raw.po"):
- lang = os.path.basename(po)[:-3]
- msgs = utils.I18nMessages(kind='PO', src=os.path.join(TRUNK_PO_DIR, po))
- stats[lang] = msgs.nbr_trans_msgs / msgs.nbr_msgs
-
- # Generate languages file used by Blender's i18n system.
- # First, match all entries in LANGUAGES to a lang in stats, if possible!
- stats = find_matching_po(LANGUAGES, stats, forbidden)
- limits = sorted(LANGUAGES_CATEGORIES, key=lambda it: it[0], reverse=True)
- idx = 0
- stats = sorted(stats, key=lambda it: it[0], reverse=True)
- langs_cats = [[] for i in range(len(limits))]
- highest_uid = 0
- for prop, uid, label, key, flag in stats:
- if prop < limits[idx][0]:
- # Sub-sort languages by iso-codes.
- langs_cats[idx].sort(key=lambda it: it[2])
- idx += 1
- if prop < min_trans and flag == OK:
- flag = TOOLOW
- langs_cats[idx].append((uid, label, key, flag))
- if abs(uid) > highest_uid:
- highest_uid = abs(uid)
- # Sub-sort last group of languages by iso-codes!
- langs_cats[idx].sort(key=lambda it: it[2])
- with open(os.path.join(TRUNK_MO_DIR, LANGUAGES_FILE), 'w', encoding="utf-8") as f:
- f.write("# File used by Blender to know which languages (translations) are available, \n")
- f.write("# and to generate translation menu.\n")
- f.write("#\n")
- f.write("# File format:\n")
- f.write("# ID:MENULABEL:ISOCODE\n")
- f.write("# ID must be unique, except for 0 value (marks categories for menu).\n")
- f.write("# Line starting with a # are comments!\n")
- f.write("#\n")
- f.write("# Automatically generated by bl_i18n_utils/update_languages_menu.py script.\n")
- f.write("# Highest ID currently in use: {}\n".format(highest_uid))
- for cat, langs_cat in zip(limits, langs_cats):
- f.write("#\n")
- # Write "category menu label"...
- if langs_cat:
- f.write("0:{}::\n".format(cat[1]))
- else:
- # Do not write the category if it has no language!
- f.write("# Void category! #0:{}:\n".format(cat[1]))
- # ...and all matching language entries!
- for uid, label, key, flag in langs_cat:
- if flag == OK:
- f.write("{}:{}:{}\n".format(uid, label, key))
- else:
- # Non-existing, commented entry!
- f.write("# {} #{}:{}:{}\n".format(FLAG_MESSAGES[flag], uid, label, key))
-
-
-if __name__ == "__main__":
- print("\n\n *** Running {} *** \n".format(__file__))
- sys.exit(main())
diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py
index f7a74808d47..f9890d79144 100644
--- a/release/scripts/modules/bl_i18n_utils/utils.py
+++ b/release/scripts/modules/bl_i18n_utils/utils.py
@@ -23,38 +23,21 @@
import collections
import concurrent.futures
import copy
+import hashlib
import os
import re
+import struct
import sys
+import tempfile
+#import time
-from bl_i18n_utils import settings
+from bl_i18n_utils import settings, rtl_utils
-
-PO_COMMENT_PREFIX = settings.PO_COMMENT_PREFIX
-PO_COMMENT_PREFIX_MSG = settings.PO_COMMENT_PREFIX_MSG
-PO_COMMENT_PREFIX_SOURCE = settings.PO_COMMENT_PREFIX_SOURCE
-PO_COMMENT_PREFIX_SOURCE_CUSTOM = settings.PO_COMMENT_PREFIX_SOURCE_CUSTOM
-PO_COMMENT_FUZZY = settings.PO_COMMENT_FUZZY
-PO_MSGCTXT = settings.PO_MSGCTXT
-PO_MSGID = settings.PO_MSGID
-PO_MSGSTR = settings.PO_MSGSTR
-
-PO_HEADER_KEY = settings.PO_HEADER_KEY
-PO_HEADER_COMMENT = settings.PO_HEADER_COMMENT
-PO_HEADER_COMMENT_COPYRIGHT = settings.PO_HEADER_COMMENT_COPYRIGHT
-PO_HEADER_MSGSTR = settings.PO_HEADER_MSGSTR
-
-PARSER_CACHE_HASH = settings.PARSER_CACHE_HASH
-
-WARN_NC = settings.WARN_MSGID_NOT_CAPITALIZED
-NC_ALLOWED = settings.WARN_MSGID_NOT_CAPITALIZED_ALLOWED
-PARSER_CACHE_HASH = settings.PARSER_CACHE_HASH
+import bpy
##### Misc Utils #####
-
-def stripeol(s):
- return s.rstrip("\n\r")
+from bpy.app.translations import locale_explode
_valid_po_path_re = re.compile(r"^\S+:[0-9]+$")
@@ -91,14 +74,64 @@ def get_best_similar(data):
return key, tmp
+def locale_match(loc1, loc2):
+ """
+ Return:
+ -n if loc1 is a subtype of loc2 (e.g. 'fr_FR' is a subtype of 'fr').
+ +n if loc2 is a subtype of loc1.
+ n becomes smaller when both locales are more similar (e.g. (sr, sr_SR) are more similar than (sr, sr_SR@latin)).
+ 0 if they are exactly the same.
+ ... (Ellipsis) if they cannot match!
+ Note: We consider that 'sr_SR@latin' is a subtype of 'sr@latin', 'sr_SR' and 'sr', but 'sr_SR' and 'sr@latin' won't
+ match (will return ...)!
+ Note: About similarity, diff in variants are more important than diff in countries, currently here are the cases:
+ (sr, sr_SR) -> 1
+ (sr@latin, sr_SR@latin) -> 1
+ (sr, sr@latin) -> 2
+ (sr_SR, sr_SR@latin) -> 2
+ (sr, sr_SR@latin) -> 3
+ """
+ if loc1 == loc2:
+ return 0
+ l1, c1, v1, *_1 = locale_explode(loc1)
+ l2, c2, v2, *_2 = locale_explode(loc2)
+
+ if l1 == l2:
+ if c1 == c2:
+ if v1 == v2:
+ return 0
+ elif v2 is None:
+ return -2
+ elif v1 is None:
+ return 2
+ return ...
+ elif c2 is None:
+ if v1 == v2:
+ return -1
+ elif v2 is None:
+ return -3
+ return ...
+ elif c1 is None:
+ if v1 == v2:
+ return 1
+ elif v1 is None:
+ return 3
+ return ...
+ return ...
+
+
+##### Main Classes #####
+
class I18nMessage:
"""
Internal representation of a message.
"""
- __slots__ = ("msgctxt_lines", "msgid_lines", "msgstr_lines", "comment_lines", "is_fuzzy", "is_commented")
+ __slots__ = ("msgctxt_lines", "msgid_lines", "msgstr_lines", "comment_lines", "is_fuzzy", "is_commented",
+ "settings")
def __init__(self, msgctxt_lines=[], msgid_lines=[], msgstr_lines=[], comment_lines=[],
- is_commented=False, is_fuzzy=False):
+ is_commented=False, is_fuzzy=False, settings=settings):
+ self.settings = settings
self.msgctxt_lines = msgctxt_lines
self.msgid_lines = msgid_lines
self.msgstr_lines = msgstr_lines
@@ -107,42 +140,42 @@ class I18nMessage:
self.is_commented = is_commented
def _get_msgctxt(self):
- return ("".join(self.msgctxt_lines)).replace("\\n", "\n")
+ return "".join(self.msgctxt_lines)
def _set_msgctxt(self, ctxt):
self.msgctxt_lines = [ctxt]
msgctxt = property(_get_msgctxt, _set_msgctxt)
def _get_msgid(self):
- return ("".join(self.msgid_lines)).replace("\\n", "\n")
+ return "".join(self.msgid_lines)
def _set_msgid(self, msgid):
self.msgid_lines = [msgid]
msgid = property(_get_msgid, _set_msgid)
def _get_msgstr(self):
- return ("".join(self.msgstr_lines)).replace("\\n", "\n")
+ return "".join(self.msgstr_lines)
def _set_msgstr(self, msgstr):
self.msgstr_lines = [msgstr]
msgstr = property(_get_msgstr, _set_msgstr)
def _get_sources(self):
- lstrip1 = len(PO_COMMENT_PREFIX_SOURCE)
- lstrip2 = len(PO_COMMENT_PREFIX_SOURCE_CUSTOM)
- return ([l[lstrip1:] for l in self.comment_lines if l.startswith(PO_COMMENT_PREFIX_SOURCE)] +
- [l[lstrip2:] for l in self.comment_lines if l.startswith(PO_COMMENT_PREFIX_SOURCE_CUSTOM)])
+ lstrip1 = len(self.settings.PO_COMMENT_PREFIX_SOURCE)
+ lstrip2 = len(self.settings.PO_COMMENT_PREFIX_SOURCE_CUSTOM)
+ return ([l[lstrip1:] for l in self.comment_lines if l.startswith(self.settings.PO_COMMENT_PREFIX_SOURCE)] +
+ [l[lstrip2:] for l in self.comment_lines
+ if l.startswith(self.settings.PO_COMMENT_PREFIX_SOURCE_CUSTOM)])
def _set_sources(self, sources):
- # list.copy() is not available in py3.2 ...
- cmmlines = []
- cmmlines[:] = self.comment_lines
+ cmmlines = self.comment_lines.copy()
for l in cmmlines:
- if l.startswith(PO_COMMENT_PREFIX_SOURCE) or l.startswith(PO_COMMENT_PREFIX_SOURCE_CUSTOM):
+ if (l.startswith(self.settings.PO_COMMENT_PREFIX_SOURCE) or
+ l.startswith(self.settings.PO_COMMENT_PREFIX_SOURCE_CUSTOM)):
self.comment_lines.remove(l)
lines_src = []
lines_src_custom = []
for src in sources:
if is_valid_po_path(src):
- lines_src.append(PO_COMMENT_PREFIX_SOURCE + src)
+ lines_src.append(self.settings.PO_COMMENT_PREFIX_SOURCE + src)
else:
- lines_src_custom.append(PO_COMMENT_PREFIX_SOURCE_CUSTOM + src)
+ lines_src_custom.append(self.settings.PO_COMMENT_PREFIX_SOURCE_CUSTOM + src)
self.comment_lines += lines_src_custom + lines_src
sources = property(_get_sources, _set_sources)
@@ -151,18 +184,29 @@ class I18nMessage:
return len(self.msgid) > 30
is_tooltip = property(_get_is_tooltip)
+ def copy(self):
+ # Deepcopy everything but the settings!
+ return self.__class__(msgctxt_lines=self.msgctxt_lines[:], msgid_lines=self.msgid_lines[:],
+ msgstr_lines=self.msgstr_lines[:], comment_lines=self.comment_lines[:],
+ is_commented=self.is_commented, is_fuzzy=self.is_fuzzy, settings=self.settings)
+
def normalize(self, max_len=80):
"""
Normalize this message, call this before exporting it...
Currently normalize msgctxt, msgid and msgstr lines to given max_len (if below 1, make them single line).
"""
max_len -= 2 # The two quotes!
+
+ def _splitlines(text):
+ lns = text.splitlines()
+ return [l + "\n" for l in lns[:-1]] + lns[-1:]
+
# We do not need the full power of textwrap... We just split first at escaped new lines, then into each line
# if needed... No word splitting, nor fancy spaces handling!
def _wrap(text, max_len, init_len):
if len(text) + init_len < max_len:
return [text]
- lines = text.splitlines()
+ lines = _splitlines(text)
ret = []
for l in lines:
tmp = []
@@ -178,25 +222,70 @@ class I18nMessage:
if tmp:
ret.append(" ".join(tmp))
return ret
+
if max_len < 1:
- self.msgctxt_lines = self.msgctxt.replace("\n", "\\n\n").splitlines()
- self.msgid_lines = self.msgid.replace("\n", "\\n\n").splitlines()
- self.msgstr_lines = self.msgstr.replace("\n", "\\n\n").splitlines()
+ self.msgctxt_lines = _splitlines(self.msgctxt)
+ self.msgid_lines = _splitlines(self.msgid)
+ self.msgstr_lines = _splitlines(self.msgstr)
else:
- init_len = len(PO_MSGCTXT) + 1
+ init_len = len(self.settings.PO_MSGCTXT) + 1
if self.is_commented:
- init_len += len(PO_COMMENT_PREFIX_MSG)
- self.msgctxt_lines = _wrap(self.msgctxt.replace("\n", "\\n\n"), max_len, init_len)
+ init_len += len(self.settings.PO_COMMENT_PREFIX_MSG)
+ self.msgctxt_lines = _wrap(self.msgctxt, max_len, init_len)
- init_len = len(PO_MSGID) + 1
+ init_len = len(self.settings.PO_MSGID) + 1
if self.is_commented:
- init_len += len(PO_COMMENT_PREFIX_MSG)
- self.msgid_lines = _wrap(self.msgid.replace("\n", "\\n\n"), max_len, init_len)
+ init_len += len(self.settings.PO_COMMENT_PREFIX_MSG)
+ self.msgid_lines = _wrap(self.msgid, max_len, init_len)
- init_len = len(PO_MSGSTR) + 1
+ init_len = len(self.settings.PO_MSGSTR) + 1
if self.is_commented:
- init_len += len(PO_COMMENT_PREFIX_MSG)
- self.msgstr_lines = _wrap(self.msgstr.replace("\n", "\\n\n"), max_len, init_len)
+ init_len += len(self.settings.PO_COMMENT_PREFIX_MSG)
+ self.msgstr_lines = _wrap(self.msgstr, max_len, init_len)
+
+ # Be sure comment lines are not duplicated (can happen with sources...).
+ tmp = []
+ for l in self.comment_lines:
+ if l not in tmp:
+ tmp.append(l)
+ self.comment_lines = tmp
+
+ _esc_quotes = re.compile(r'(?!<\\)((?:\\\\)*)"')
+ _unesc_quotes = re.compile(r'(?!<\\)((?:\\\\)*)\\"')
+ _esc_names = ("msgctxt_lines", "msgid_lines", "msgstr_lines")
+ _esc_names_all = _esc_names + ("comment_lines",)
+
+ @classmethod
+ def do_escape(cls, txt):
+ """Replace some chars by their escaped versions!"""
+ if "\n" in txt:
+ txt = txt.replace("\n", r"\n")
+ if "\t" in txt:
+ txt.replace("\t", r"\t")
+ if '"' in txt:
+ txt = cls._esc_quotes.sub(r'\1\"', txt)
+ return txt
+
+ @classmethod
+ def do_unescape(cls, txt):
+ """Replace escaped chars by real ones!"""
+ if r"\n" in txt:
+ txt = txt.replace(r"\n", "\n")
+ if r"\t" in txt:
+ txt = txt.replace(r"\t", "\t")
+ if r'\"' in txt:
+ txt = cls._unesc_quotes.sub(r'\1"', txt)
+ return txt
+
+ def escape(self, do_all=False):
+ names = self._esc_names_all if do_all else self._esc_names
+ for name in names:
+ setattr(self, name, [self.do_escape(l) for l in getattr(self, name)])
+
+ def unescape(self, do_all=True):
+ names = self._esc_names_all if do_all else self._esc_names
+ for name in names:
+ setattr(self, name, [self.do_unescape(l) for l in getattr(self, name)])
class I18nMessages:
@@ -207,10 +296,11 @@ class I18nMessages:
# Avoid parsing again!
# Keys should be (pseudo) file-names, values are tuples (hash, I18nMessages)
# Note: only used by po parser currently!
- _parser_cache = {}
+ #_parser_cache = {}
- def __init__(self, iso="__POT__", kind=None, key=None, src=None):
- self.iso = iso
+ def __init__(self, uid=None, kind=None, key=None, src=None, settings=settings):
+ self.settings = settings
+ self.uid = uid if uid is not None else settings.PARSER_TEMPLATE_ID
self.msgs = self._new_messages()
self.trans_msgs = set()
self.fuzzy_msgs = set()
@@ -229,22 +319,26 @@ class I18nMessages:
self.parse(kind, key, src)
self.update_info()
+ self._reverse_cache = None
+
@staticmethod
def _new_messages():
return getattr(collections, 'OrderedDict', dict)()
@classmethod
- def gen_empty_messages(cls, iso, blender_ver, blender_rev, time, year, default_copyright=True):
+ def gen_empty_messages(cls, uid, blender_ver, blender_rev, time, year, default_copyright=True, settings=settings):
"""Generate an empty I18nMessages object (only header is present!)."""
- msgstr = PO_HEADER_MSGSTR.format(blender_ver=str(blender_ver), blender_rev=int(blender_rev),
- time=str(time), iso=str(iso))
+ fmt = settings.PO_HEADER_MSGSTR
+ msgstr = fmt.format(blender_ver=str(blender_ver), blender_rev=int(blender_rev), time=str(time), uid=str(uid))
comment = ""
if default_copyright:
- comment = PO_HEADER_COMMENT_COPYRIGHT.format(year=str(year))
- comment = comment + PO_HEADER_COMMENT
+ comment = settings.PO_HEADER_COMMENT_COPYRIGHT.format(year=str(year))
+ comment = comment + settings.PO_HEADER_COMMENT
- msgs = cls(iso=iso)
- msgs.msgs[PO_HEADER_KEY] = I18nMessage([], [""], [msgstr], [comment], False, True)
+ msgs = cls(uid=uid, settings=settings)
+ key = settings.PO_HEADER_KEY
+ msgs.msgs[key] = I18nMessage([key[0]], [key[1]], msgstr.split("\n"), comment.split("\n"),
+ False, False, settings=settings)
msgs.update_info()
return msgs
@@ -253,16 +347,79 @@ class I18nMessages:
for msg in self.msgs.values():
msg.normalize(max_len)
+ def escape(self, do_all=False):
+ for msg in self.msgs.values():
+ msg.escape(do_all)
+
+ def unescape(self, do_all=True):
+ for msg in self.msgs.values():
+ msg.unescape(do_all)
+
+ def check(self, fix=False):
+ """
+ Check consistency between messages and their keys!
+ Check messages using format stuff are consistant between msgid and msgstr!
+ If fix is True, tries to fix the issues.
+ Return a list of found errors (empty if everything went OK!).
+ """
+ ret = []
+ default_context = self.settings.DEFAULT_CONTEXT
+ _format = re.compile("%[.0-9]*[tslfd]").findall
+ done_keys = set()
+ tmp = {}
+ rem = set()
+ for key, msg in self.msgs.items():
+ msgctxt, msgid, msgstr = msg.msgctxt, msg.msgid, msg.msgstr
+ real_key = (msgctxt or default_context, msgid)
+ if key != real_key:
+ ret.append("Error! msg's context/message do not match its key ({} / {})".format(real_key, key))
+ if real_key in self.msgs:
+ ret.append("Error! msg's real_key already used!")
+ if fix:
+ rem.add(real_key)
+ elif fix:
+ tmp[real_key] = msg
+ done_keys.add(key)
+ if '%' in msgid and msgstr and len(_format(msgid)) != len(_format(msgstr)):
+ ret.append("Error! msg's format entities are not matched in msgid and msgstr ({})".format(real_key))
+ if fix:
+ msg.msgstr = ""
+ for k in rem:
+ del self.msgs[k]
+ self.msgs.update(tmp)
+ return ret
+
+ def clean_commented(self):
+ self.update_info()
+ nbr = len(self.comm_msgs)
+ for k in self.comm_msgs:
+ del self.msgs[k]
+ return nbr
+
+ def rtl_process(self):
+ keys = []
+ trans = []
+ for k, m in self.msgs.items():
+ keys.append(k)
+ trans.append(m.msgstr)
+ trans = rtl_utils.log2vis(trans, self.settings)
+ for k, t in zip(keys, trans):
+ self.msgs[k].msgstr = t
+
def merge(self, replace=False, *args):
+ # TODO
pass
- def update(self, ref, use_similar=0.75, keep_old_commented=True):
+ def update(self, ref, use_similar=None, keep_old_commented=True):
"""
Update this I18nMessage with the ref one. Translations from ref are never used. Source comments from ref
completely replace current ones. If use_similar is not 0.0, it will try to match new messages in ref with an
existing one. Messages no more found in ref will be marked as commented if keep_old_commented is True,
or removed.
"""
+ if use_similar is None:
+ use_similar = self.settings.SIMILAR_MSGID_THRESHOLD
+
similar_pool = {}
if use_similar > 0.0:
for key, msg in self.msgs.items():
@@ -280,7 +437,6 @@ class I18nMessages:
msg, refmsg = self.msgs[key], ref.msgs[key]
msg.sources = refmsg.sources
msg.is_commented = refmsg.is_commented
- msg.is_fuzzy = refmsg.is_fuzzy
msgs[key] = msg
# Next process new keys.
@@ -294,7 +450,7 @@ class I18nMessages:
if skey not in similar_pool[msgid]:
skey = tuple(similar_pool[msgid])[0]
# We keep org translation and comments, and mark message as fuzzy.
- msg, refmsg = copy.deepcopy(self.msgs[skey]), ref.msgs[key]
+ msg, refmsg = self.msgs[skey].copy(), ref.msgs[key]
msg.msgctxt = refmsg.msgctxt
msg.msgid = refmsg.msgid
msg.sources = refmsg.sources
@@ -316,7 +472,7 @@ class I18nMessages:
msgs[key].sources = []
# Special 'meta' message, change project ID version and pot creation date...
- key = ("", "")
+ key = self.settings.PO_HEADER_KEY
rep = []
markers = ("Project-Id-Version:", "POT-Creation-Date:")
for mrk in markers:
@@ -340,7 +496,7 @@ class I18nMessages:
self.nbr_signs = 0
self.nbr_trans_signs = 0
for key, msg in self.msgs.items():
- if key == PO_HEADER_KEY:
+ if key == self.settings.PO_HEADER_KEY:
continue
if msg.is_commented:
self.comm_msgs.add(key)
@@ -360,7 +516,7 @@ class I18nMessages:
self.nbr_trans_ttips = len(self.ttip_msgs & self.trans_msgs)
self.nbr_comm_msgs = len(self.comm_msgs)
- def print_stats(self, prefix=""):
+ def print_stats(self, prefix="", output=print):
"""
Print out some stats about an I18nMessages object.
"""
@@ -390,7 +546,149 @@ class I18nMessages:
"{:>6.1%} of messages are commented ({} over {}).\n"
"".format(lvl_comm, self.nbr_comm_msgs, self.nbr_comm_msgs + self.nbr_msgs),
"This translation is currently made of {} signs.\n".format(self.nbr_trans_signs))
- print(prefix.join(lines))
+ output(prefix.join(lines))
+
+ def invalidate_reverse_cache(self, rebuild_now=False):
+ """
+ Invalidate the reverse cache used by find_best_messages_matches.
+ """
+ self._reverse_cache = None
+ if rebuild_now:
+ src_to_msg, ctxt_to_msg, msgid_to_msg, msgstr_to_msg = {}, {}, {}, {}
+ for key, msg in self.msgs.items():
+ if msg.is_commented:
+ continue
+ ctxt, msgid = key
+ ctxt_to_msg.setdefault(ctxt, set()).add(key)
+ msgid_to_msg.setdefault(msgid, set()).add(key)
+ msgstr_to_msg.setdefault(msg.msgstr, set()).add(key)
+ for src in msg.sources:
+ src_to_msg.setdefault(src, set()).add(key)
+ self._reverse_cache = (src_to_msg, ctxt_to_msg, msgid_to_msg, msgstr_to_msg)
+
+ def find_best_messages_matches(self, msgs, msgmap, rna_ctxt, rna_struct_name, rna_prop_name, rna_enum_name):
+ """
+ Try to find the best I18nMessages (i.e. context/msgid pairs) for the given UI messages:
+ msgs: an object containing properties listed in msgmap's values.
+ msgmap: a dict of various messages to use for search:
+ {"but_label": subdict, "rna_label": subdict, "enum_label": subdict,
+ "but_tip": subdict, "rna_tip": subdict, "enum_tip": subdict}
+ each subdict being like that:
+ {"msgstr": id, "msgid": id, "msg_flags": id, "key": set()}
+ where msgstr and msgid are identifiers of string props in msgs (resp. translated and org message),
+ msg_flags is not used here, and key is a set of matching (msgctxt, msgid) keys for the item.
+ The other parameters are about the RNA element from which the strings come from, if it could be determined:
+ rna_ctxt: the labels' i18n context.
+ rna_struct_name, rna_prop_name, rna_enum_name: should be self-explanatory!
+ """
+ # Build helper mappings.
+ # Note it's user responsibility to know when to invalidate (and hence force rebuild) this cache!
+ if self._reverse_cache is None:
+ self.invalidate_reverse_cache(True)
+ src_to_msg, ctxt_to_msg, msgid_to_msg, msgstr_to_msg = self._reverse_cache
+
+ # print(len(src_to_msg), len(ctxt_to_msg), len(msgid_to_msg), len(msgstr_to_msg))
+
+ # Build RNA key.
+ src, src_rna, src_enum = bpy.utils.make_rna_paths(rna_struct_name, rna_prop_name, rna_enum_name)
+ print("src: ", src_rna, src_enum)
+
+ # Labels.
+ elbl = getattr(msgs, msgmap["enum_label"]["msgstr"])
+ if elbl:
+ # Enum items' labels have no i18n context...
+ k = ctxt_to_msg[self.settings.DEFAULT_CONTEXT].copy()
+ if elbl in msgid_to_msg:
+ k &= msgid_to_msg[elbl]
+ elif elbl in msgstr_to_msg:
+ k &= msgstr_to_msg[elbl]
+ else:
+ k = set()
+ # We assume if we already have only one key, it's the good one!
+ if len(k) > 1 and src_enum in src_to_msg:
+ k &= src_to_msg[src_enum]
+ msgmap["enum_label"]["key"] = k
+ rlbl = getattr(msgs, msgmap["rna_label"]["msgstr"])
+ #print("rna label: " + rlbl, rlbl in msgid_to_msg, rlbl in msgstr_to_msg)
+ if rlbl:
+ k = ctxt_to_msg[rna_ctxt].copy()
+ if k and rlbl in msgid_to_msg:
+ k &= msgid_to_msg[rlbl]
+ elif k and rlbl in msgstr_to_msg:
+ k &= msgstr_to_msg[rlbl]
+ else:
+ k = set()
+ # We assume if we already have only one key, it's the good one!
+ if len(k) > 1 and src_rna in src_to_msg:
+ k &= src_to_msg[src_rna]
+ msgmap["rna_label"]["key"] = k
+ blbl = getattr(msgs, msgmap["but_label"]["msgstr"])
+ blbls = [blbl]
+ if blbl.endswith(self.settings.NUM_BUTTON_SUFFIX):
+ # Num buttons report their label with a trailing ': '...
+ blbls.append(blbl[:-len(self.settings.NUM_BUTTON_SUFFIX)])
+ print("button label: " + blbl)
+ if blbl and elbl not in blbls and (rlbl not in blbls or rna_ctxt != self.settings.DEFAULT_CONTEXT):
+ # Always Default context for button label :/
+ k = ctxt_to_msg[self.settings.DEFAULT_CONTEXT].copy()
+ found = False
+ for bl in blbls:
+ if bl in msgid_to_msg:
+ k &= msgid_to_msg[bl]
+ found = True
+ break
+ elif bl in msgstr_to_msg:
+ k &= msgstr_to_msg[bl]
+ found = True
+ break
+ if not found:
+ k = set()
+ # XXX No need to check against RNA path here, if blabel is different
+ # from rlabel, should not match anyway!
+ msgmap["but_label"]["key"] = k
+
+ # Tips (they never have a specific context).
+ etip = getattr(msgs, msgmap["enum_tip"]["msgstr"])
+ #print("enum tip: " + etip)
+ if etip:
+ k = ctxt_to_msg[self.settings.DEFAULT_CONTEXT].copy()
+ if etip in msgid_to_msg:
+ k &= msgid_to_msg[etip]
+ elif etip in msgstr_to_msg:
+ k &= msgstr_to_msg[etip]
+ else:
+ k = set()
+ # We assume if we already have only one key, it's the good one!
+ if len(k) > 1 and src_enum in src_to_msg:
+ k &= src_to_msg[src_enum]
+ msgmap["enum_tip"]["key"] = k
+ rtip = getattr(msgs, msgmap["rna_tip"]["msgstr"])
+ #print("rna tip: " + rtip)
+ if rtip:
+ k = ctxt_to_msg[self.settings.DEFAULT_CONTEXT].copy()
+ if k and rtip in msgid_to_msg:
+ k &= msgid_to_msg[rtip]
+ elif k and rtip in msgstr_to_msg:
+ k &= msgstr_to_msg[rtip]
+ else:
+ k = set()
+ # We assume if we already have only one key, it's the good one!
+ if len(k) > 1 and src_rna in src_to_msg:
+ k &= src_to_msg[src_rna]
+ msgmap["rna_tip"]["key"] = k
+ #print(k)
+ btip = getattr(msgs, msgmap["but_tip"]["msgstr"])
+ #print("button tip: " + btip)
+ if btip and btip not in {rtip, etip}:
+ k = ctxt_to_msg[self.settings.DEFAULT_CONTEXT].copy()
+ if btip in msgid_to_msg:
+ k &= msgid_to_msg[btip]
+ elif btip in msgstr_to_msg:
+ k &= msgstr_to_msg[btip]
+ else:
+ k = set()
+ # XXX No need to check against RNA path here, if btip is different from rtip, should not match anyway!
+ msgmap["but_tip"]["key"] = k
def parse(self, kind, key, src):
del self.parsing_errors[:]
@@ -419,14 +717,16 @@ class I18nMessages:
msgstr_lines = []
comment_lines = []
+ default_context = self.settings.DEFAULT_CONTEXT
+
# Helper function
def finalize_message(self, line_nr):
nonlocal reading_msgid, reading_msgstr, reading_msgctxt, reading_comment
nonlocal is_commented, is_fuzzy, msgid_lines, msgstr_lines, msgctxt_lines, comment_lines
- msgid = "".join(msgid_lines)
- msgctxt = "".join(msgctxt_lines)
- msgkey = (msgctxt, msgid)
+ msgid = I18nMessage.do_unescape("".join(msgid_lines))
+ msgctxt = I18nMessage.do_unescape("".join(msgctxt_lines))
+ msgkey = (msgctxt or default_context, msgid)
# Never allow overriding existing msgid/msgctxt pairs!
if msgkey in self.msgs:
@@ -434,7 +734,7 @@ class I18nMessages:
return
self.msgs[msgkey] = I18nMessage(msgctxt_lines, msgid_lines, msgstr_lines, comment_lines,
- is_commented, is_fuzzy)
+ is_commented, is_fuzzy, settings=self.settings)
# Let's clean up and get ready for next message!
reading_msgid = reading_msgstr = reading_msgctxt = reading_comment = False
@@ -445,32 +745,31 @@ class I18nMessages:
comment_lines = []
# try to use src as file name...
- if os.path.exists(src):
+ if os.path.isfile(src):
+ if os.stat(src).st_size > self.settings.PARSER_MAX_FILE_SIZE:
+ # Security, else we could read arbitrary huge files!
+ print("WARNING: skipping file {}, too huge!".format(src))
+ return
if not key:
key = src
with open(src, 'r', encoding="utf-8") as f:
src = f.read()
- # Try to use values from cache!
- curr_hash = None
- if key and key in self._parser_cache:
- old_hash, msgs = self._parser_cache[key]
- import hashlib
- curr_hash = hashlib.new(PARSER_CACHE_HASH, src.encode()).digest()
- if curr_hash == old_hash:
- self.msgs = copy.deepcopy(msgs) # we might edit self.msgs!
- return
-
- _comm_msgctxt = PO_COMMENT_PREFIX_MSG + PO_MSGCTXT
- _len_msgctxt = len(PO_MSGCTXT + '"')
+ _msgctxt = self.settings.PO_MSGCTXT
+ _comm_msgctxt = self.settings.PO_COMMENT_PREFIX_MSG + _msgctxt
+ _len_msgctxt = len(_msgctxt + '"')
_len_comm_msgctxt = len(_comm_msgctxt + '"')
- _comm_msgid = PO_COMMENT_PREFIX_MSG + PO_MSGID
- _len_msgid = len(PO_MSGID + '"')
+ _msgid = self.settings.PO_MSGID
+ _comm_msgid = self.settings.PO_COMMENT_PREFIX_MSG + _msgid
+ _len_msgid = len(_msgid + '"')
_len_comm_msgid = len(_comm_msgid + '"')
- _comm_msgstr = PO_COMMENT_PREFIX_MSG + PO_MSGSTR
- _len_msgstr = len(PO_MSGSTR + '"')
+ _msgstr = self.settings.PO_MSGSTR
+ _comm_msgstr = self.settings.PO_COMMENT_PREFIX_MSG + _msgstr
+ _len_msgstr = len(_msgstr + '"')
_len_comm_msgstr = len(_comm_msgstr + '"')
- _len_comm_str = len(PO_COMMENT_PREFIX_MSG + '"')
+ _comm_str = self.settings.PO_COMMENT_PREFIX_MSG
+ _comm_fuzzy = self.settings.PO_COMMENT_FUZZY
+ _len_comm_str = len(_comm_str + '"')
# Main loop over all lines in src...
for line_nr, line in enumerate(src.splitlines()):
@@ -479,20 +778,20 @@ class I18nMessages:
finalize_message(self, line_nr)
continue
- elif line.startswith(PO_MSGCTXT) or line.startswith(_comm_msgctxt):
+ elif line.startswith(_msgctxt) or line.startswith(_comm_msgctxt):
reading_comment = False
reading_ctxt = True
- if line.startswith(PO_COMMENT_PREFIX_MSG):
+ if line.startswith(_comm_str):
is_commented = True
line = line[_len_comm_msgctxt:-1]
else:
line = line[_len_msgctxt:-1]
msgctxt_lines.append(line)
- elif line.startswith(PO_MSGID) or line.startswith(_comm_msgid):
+ elif line.startswith(_msgid) or line.startswith(_comm_msgid):
reading_comment = False
reading_msgid = True
- if line.startswith(PO_COMMENT_PREFIX_MSG):
+ if line.startswith(_comm_str):
if not is_commented and reading_ctxt:
self.parsing_errors.append((line_nr, "commented msgid following regular msgctxt"))
is_commented = True
@@ -502,13 +801,13 @@ class I18nMessages:
reading_ctxt = False
msgid_lines.append(line)
- elif line.startswith(PO_MSGSTR) or line.startswith(_comm_msgstr):
+ elif line.startswith(_msgstr) or line.startswith(_comm_msgstr):
if not reading_msgid:
self.parsing_errors.append((line_nr, "msgstr without a prior msgid"))
else:
reading_msgid = False
reading_msgstr = True
- if line.startswith(PO_COMMENT_PREFIX_MSG):
+ if line.startswith(_comm_str):
line = line[_len_comm_msgstr:-1]
if not is_commented:
self.parsing_errors.append((line_nr, "commented msgstr following regular msgid"))
@@ -518,8 +817,8 @@ class I18nMessages:
self.parsing_errors.append((line_nr, "regular msgstr following commented msgid"))
msgstr_lines.append(line)
- elif line.startswith(PO_COMMENT_PREFIX[0]):
- if line.startswith(PO_COMMENT_PREFIX_MSG):
+ elif line.startswith(_comm_str[0]):
+ if line.startswith(_comm_str):
if reading_msgctxt:
if is_commented:
msgctxt_lines.append(line[_len_comm_str:-1])
@@ -542,7 +841,7 @@ class I18nMessages:
if reading_msgctxt or reading_msgid or reading_msgstr:
self.parsing_errors.append((line_nr,
"commented string within msgctxt, msgid or msgstr scope, ignored"))
- elif line.startswith(PO_COMMENT_FUZZY):
+ elif line.startswith(_comm_fuzzy):
is_fuzzy = True
else:
comment_lines.append(line)
@@ -563,12 +862,7 @@ class I18nMessages:
# If no final empty line, last message is not finalized!
if reading_msgstr:
finalize_message(self, line_nr)
-
- if key:
- if not curr_hash:
- import hashlib
- curr_hash = hashlib.new(PARSER_CACHE_HASH, src.encode()).digest()
- self._parser_cache[key] = (curr_hash, self.msgs)
+ self.unescape()
def write(self, kind, dest):
self.writers[kind](self, dest)
@@ -577,54 +871,139 @@ class I18nMessages:
"""
Write messages in fname po file.
"""
- self.normalize(max_len=0) # No wrapping for now...
- with open(fname, 'w', encoding="utf-8") as f:
- for msg in self.msgs.values():
+ default_context = self.settings.DEFAULT_CONTEXT
+
+ def _write(self, f):
+ _msgctxt = self.settings.PO_MSGCTXT
+ _msgid = self.settings.PO_MSGID
+ _msgstr = self.settings.PO_MSGSTR
+ _comm = self.settings.PO_COMMENT_PREFIX_MSG
+
+ self.escape()
+
+ for num, msg in enumerate(self.msgs.values()):
f.write("\n".join(msg.comment_lines))
# Only mark as fuzzy if msgstr is not empty!
if msg.is_fuzzy and msg.msgstr:
- f.write("\n" + PO_COMMENT_FUZZY)
- _p = PO_COMMENT_PREFIX_MSG if msg.is_commented else ""
- _pmsgctxt = _p + PO_MSGCTXT
- _pmsgid = _p + PO_MSGID
- _pmsgstr = _p + PO_MSGSTR
+ f.write("\n" + self.settings.PO_COMMENT_FUZZY)
+ _p = _comm if msg.is_commented else ""
chunks = []
- if msg.msgctxt:
+ if msg.msgctxt and msg.msgctxt != default_context:
if len(msg.msgctxt_lines) > 1:
chunks += [
- "\n" + _pmsgctxt + "\"\"\n" + _p + "\"",
+ "\n" + _p + _msgctxt + "\"\"\n" + _p + "\"",
("\"\n" + _p + "\"").join(msg.msgctxt_lines),
"\"",
]
else:
- chunks += ["\n" + _pmsgctxt + "\"" + msg.msgctxt + "\""]
+ chunks += ["\n" + _p + _msgctxt + "\"" + msg.msgctxt + "\""]
if len(msg.msgid_lines) > 1:
chunks += [
- "\n" + _pmsgid + "\"\"\n" + _p + "\"",
+ "\n" + _p + _msgid + "\"\"\n" + _p + "\"",
("\"\n" + _p + "\"").join(msg.msgid_lines),
"\"",
]
else:
- chunks += ["\n" + _pmsgid + "\"" + msg.msgid + "\""]
+ chunks += ["\n" + _p + _msgid + "\"" + msg.msgid + "\""]
if len(msg.msgstr_lines) > 1:
chunks += [
- "\n" + _pmsgstr + "\"\"\n" + _p + "\"",
+ "\n" + _p + _msgstr + "\"\"\n" + _p + "\"",
("\"\n" + _p + "\"").join(msg.msgstr_lines),
"\"",
]
else:
- chunks += ["\n" + _pmsgstr + "\"" + msg.msgstr + "\""]
+ chunks += ["\n" + _p + _msgstr + "\"" + msg.msgstr + "\""]
chunks += ["\n\n"]
f.write("".join(chunks))
+ self.unescape()
+
+ self.normalize(max_len=0) # No wrapping for now...
+ if isinstance(fname, str):
+ with open(fname, 'w', encoding="utf-8") as f:
+ _write(self, f)
+ # Else assume fname is already a file(like) object!
+ else:
+ _write(self, fname)
+
+ def write_messages_to_mo(self, fname):
+ """
+ Write messages in fname mo file.
+ """
+ # XXX Temp solution, until I can make own mo generator working...
+ import subprocess
+ with tempfile.NamedTemporaryFile(mode='w+', encoding="utf-8") as tmp_po_f:
+ self.write_messages_to_po(tmp_po_f)
+ cmd = (self.settings.GETTEXT_MSGFMT_EXECUTABLE,
+ "--statistics", # show stats
+ tmp_po_f.name,
+ "-o",
+ fname,
+ )
+ print("Running ", " ".join(cmd))
+ ret = subprocess.call(cmd)
+ print("Finished.")
+ return
+ # XXX Code below is currently broken (generates corrupted mo files it seems :( )!
+ # Using http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html notation.
+ # Not generating hash table!
+ # Only translated, unfuzzy messages are taken into account!
+ default_context = self.settings.DEFAULT_CONTEXT
+ msgs = tuple(v for v in self.msgs.values() if not (v.is_fuzzy or v.is_commented) and v.msgstr and v.msgid)
+ msgs = sorted(msgs[:2],
+ key=lambda e: (e.msgctxt + e.msgid) if (e.msgctxt and e.msgctxt != default_context) else e.msgid)
+ magic_nbr = 0x950412de
+ format_rev = 0
+ N = len(msgs)
+ O = 32
+ T = O + N * 8
+ S = 0
+ H = T + N * 8
+ # Prepare our data! we need key (optional context and msgid), translation, and offset and length of both.
+ # Offset are relative to start of their own list.
+ EOT = b"0x04" # Used to concatenate context and msgid
+ _msgid_offset = 0
+ _msgstr_offset = 0
+ def _gen(v):
+ nonlocal _msgid_offset, _msgstr_offset
+ msgid = v.msgid.encode("utf-8")
+ msgstr = v.msgstr.encode("utf-8")
+ if v.msgctxt and v.msgctxt != default_context:
+ msgctxt = v.msgctxt.encode("utf-8")
+ msgid = msgctxt + EOT + msgid
+ # Don't forget the final NULL char!
+ _msgid_len = len(msgid) + 1
+ _msgstr_len = len(msgstr) + 1
+ ret = ((msgid, _msgid_len, _msgid_offset), (msgstr, _msgstr_len, _msgstr_offset))
+ _msgid_offset += _msgid_len
+ _msgstr_offset += _msgstr_len
+ return ret
+ msgs = tuple(_gen(v) for v in msgs)
+ msgid_start = H
+ msgstr_start = msgid_start + _msgid_offset
+ print(N, msgstr_start + _msgstr_offset)
+ print(msgs)
+
+ with open(fname, 'wb') as f:
+ # Header...
+ f.write(struct.pack("=8I", magic_nbr, format_rev, N, O, T, S, H, 0))
+ # Msgid's length and offset.
+ f.write(b"".join(struct.pack("=2I", length, msgid_start + offset) for (_1, length, offset), _2 in msgs))
+ # Msgstr's length and offset.
+ f.write(b"".join(struct.pack("=2I", length, msgstr_start + offset) for _1, (_2, length, offset) in msgs))
+ # No hash table!
+ # Msgid's.
+ f.write(b"\0".join(msgid for (msgid, _1, _2), _3 in msgs) + b"\0")
+ # Msgstr's.
+ f.write(b"\0".join(msgstr for _1, (msgstr, _2, _3) in msgs) + b"\0")
+
parsers = {
"PO": parse_messages_from_po,
-# "PYTUPLE": parse_messages_from_pytuple,
}
writers = {
"PO": write_messages_to_po,
- #"PYDICT": write_messages_to_pydict,
+ "MO": write_messages_to_mo,
}
@@ -633,10 +1012,67 @@ class I18n:
Internal representation of a whole translation set.
"""
- def __init__(self, src):
+ @staticmethod
+ def _parser_check_file(path, maxsize=settings.PARSER_MAX_FILE_SIZE, _begin_marker=None, _end_marker=None):
+ if os.stat(path).st_size > maxsize:
+ # Security, else we could read arbitrary huge files!
+ print("WARNING: skipping file {}, too huge!".format(path))
+ return None, None, None
+ txt = ""
+ with open(path) as f:
+ txt = f.read()
+ _in = 0
+ _out = len(txt)
+ if _begin_marker:
+ _in = None
+ if _begin_marker in txt:
+ _in = txt.index(_begin_marker) + len(_begin_marker)
+ if _end_marker:
+ _out = None
+ if _end_marker in txt:
+ _out = txt.index(_end_marker)
+ if _in is not None and _out is not None:
+ return txt[:_in], txt[_in:_out], txt[_out:]
+ return txt, None, None
+
+ @staticmethod
+ def _dst(self, path, uid, kind):
+ if kind == 'PO':
+ if uid == self.settings.PARSER_TEMPLATE_ID:
+ if not path.endswith(".pot"):
+ return os.path.join(os.path.dirname(path), "blender.pot")
+ if not path.endswith(".po"):
+ return os.path.join(os.path.dirname(path), uid + ".po")
+ elif kind == 'PY':
+ if not path.endswith(".py"):
+ if self.src.get(self.settings.PARSER_PY_ID):
+ return self.src[self.settings.PARSER_PY_ID]
+ return os.path.join(os.path.dirname(path), "translations.py")
+ return path
+
+ def __init__(self, kind=None, src=None, langs=set(), settings=settings):
+ self.settings = settings
self.trans = {}
+ self.src = {} # Should have the same keys as self.trans (plus PARSER_PY_ID for py file)!
+ self.dst = self._dst # A callable that transforms src_path into dst_path!
+ if kind and src:
+ self.parse(kind, src, langs)
self.update_info()
+ def _py_file_get(self):
+ return self.src.get(self.settings.PARSER_PY_ID)
+ def _py_file_set(self, value):
+ self.src[self.settings.PARSER_PY_ID] = value
+ py_file = property(_py_file_get, _py_file_set)
+
+ def escape(self, do_all=False):
+ for trans in self.trans.values():
+ trans.escape(do_all)
+
+ def unescape(self, do_all=True):
+ for trans in self.trans.values():
+ trans.unescape(do_all)
+
def update_info(self):
self.nbr_trans = 0
self.lvl = 0.0
@@ -648,12 +1084,12 @@ class I18n:
self.nbr_trans_signs = 0
self.contexts = set()
- if TEMPLATE_ISO_ID in self.trans:
+ if self.settings.PARSER_TEMPLATE_ID in self.trans:
self.nbr_trans = len(self.trans) - 1
- self.nbr_signs = self.trans[TEMPLATE_ISO_ID].nbr_signs
+ self.nbr_signs = self.trans[self.settings.PARSER_TEMPLATE_ID].nbr_signs
else:
self.nbr_trans = len(self.trans)
- for iso, msgs in self.trans.items():
+ for msgs in self.trans.values():
msgs.update_info()
if msgs.nbr_msgs > 0:
self.lvl += float(msgs.nbr_trans_msgs) / float(msgs.nbr_msgs)
@@ -675,69 +1111,299 @@ class I18n:
"""
if print_msgs:
msgs_prefix = prefix + " "
- for key, msgs in self.trans:
- if key == TEMPLATE_ISO_ID:
+ for key, msgs in self.trans.items():
+ if key == self.settings.PARSER_TEMPLATE_ID:
continue
print(prefix + key + ":")
msgs.print_stats(prefix=msgs_prefix)
print(prefix)
- nbr_contexts = len(self.contexts - {CONTEXT_DEFAULT})
+ nbr_contexts = len(self.contexts - {bpy.app.translations.contexts.default})
if nbr_contexts != 1:
if nbr_contexts == 0:
nbr_contexts = "No"
_ctx_txt = "s are"
else:
_ctx_txt = " is"
- lines = ("",
- "Average stats for all {} translations:\n".format(self.nbr_trans),
- " {:>6.1%} done!\n".format(self.lvl / self.nbr_trans),
- " {:>6.1%} of messages are tooltips.\n".format(self.lvl_ttips / self.nbr_trans),
- " {:>6.1%} of tooltips are translated.\n".format(self.lvl_trans_ttips / self.nbr_trans),
- " {:>6.1%} of translated messages are tooltips.\n".format(self.lvl_ttips_in_trans / self.nbr_trans),
- " {:>6.1%} of messages are commented.\n".format(self.lvl_comm / self.nbr_trans),
- " The org msgids are currently made of {} signs.\n".format(self.nbr_signs),
- " All processed translations are currently made of {} signs.\n".format(self.nbr_trans_signs),
- " {} specific context{} present:\n {}\n"
- "".format(self.nbr_contexts, _ctx_txt, "\n ".join(self.contexts - {CONTEXT_DEFAULT})),
- "\n")
+ lines = (("",
+ "Average stats for all {} translations:\n".format(self.nbr_trans),
+ " {:>6.1%} done!\n".format(self.lvl / self.nbr_trans),
+ " {:>6.1%} of messages are tooltips.\n".format(self.lvl_ttips / self.nbr_trans),
+ " {:>6.1%} of tooltips are translated.\n".format(self.lvl_trans_ttips / self.nbr_trans),
+ " {:>6.1%} of translated messages are tooltips.\n".format(self.lvl_ttips_in_trans / self.nbr_trans),
+ " {:>6.1%} of messages are commented.\n".format(self.lvl_comm / self.nbr_trans),
+ " The org msgids are currently made of {} signs.\n".format(self.nbr_signs),
+ " All processed translations are currently made of {} signs.\n".format(self.nbr_trans_signs),
+ " {} specific context{} present:\n".format(self.nbr_contexts, _ctx_txt)) +
+ tuple(" " + c + "\n" for c in self.contexts - {bpy.app.translations.contexts.default}) +
+ ("\n",)
+ )
print(prefix.join(lines))
+ def parse(self, kind, src, langs=set()):
+ self.parsers[kind](self, src, langs)
-##### Parsers #####
+ def parse_from_po(self, src, langs=set()):
+ """
+ src must be a tuple (dir_of_pos, pot_file), where:
+ * dir_of_pos may either contains iso_CODE.po files, and/or iso_CODE/iso_CODE.po files.
+ * pot_file may be None (in which case there will be no ref messages).
+ if langs set is void, all languages found are loaded.
+ """
+ root_dir, pot_file = src
+ if pot_file and os.path.isfile(pot_file):
+ self.trans[self.settings.PARSER_TEMPLATE_ID] = I18nMessages(self.settings.PARSER_TEMPLATE_ID, 'PO',
+ pot_file, pot_file, settings=self.settings)
+ self.src_po[self.settings.PARSER_TEMPLATE_ID] = pot_file
+
+ for p in os.listdir(root_dir):
+ uid = po_file = None
+ if p.endswith(".po") and os.path.isfile(p):
+ uid = p[:-3]
+ if langs and uid not in langs:
+ continue
+ po_file = os.path.join(root_dir, p)
+ elif os.path.isdir(p):
+ uid = p
+ if langs and uid not in langs:
+ continue
+ po_file = os.path.join(root_dir, p, p + ".po")
+ if not os.path.isfile(po_file):
+ continue
+ else:
+ continue
+ if uid in self.trans:
+ printf("WARNING! {} id has been found more than once! only first one has been loaded!".format(uid))
+ continue
+ self.trans[uid] = I18nMessages(uid, 'PO', po_file, po_file, settings=self.settings)
+ self.src_po[uid] = po_file
-#def parse_messages_from_pytuple(self, src, key=None):
- #"""
- #Returns a dict of tuples similar to the one returned by parse_messages_from_po (one per language, plus a 'pot'
- #one keyed as '__POT__').
- #"""
- ## src may be either a string to be interpreted as py code, or a real tuple!
- #if isinstance(src, str):
- #src = eval(src)
-#
- #curr_hash = None
- #if key and key in _parser_cache:
- #old_hash, ret = _parser_cache[key]
- #import hashlib
- #curr_hash = hashlib.new(PARSER_CACHE_HASH, str(src).encode()).digest()
- #if curr_hash == old_hash:
- #return ret
-#
- #pot = new_messages()
- #states = gen_states()
- #stats = gen_stats()
- #ret = {"__POT__": (pot, states, stats)}
- #for msg in src:
- #key = msg[0]
- #messages[msgkey] = gen_message(msgid_lines, msgstr_lines, comment_lines, msgctxt_lines)
- #pot[key] = gen_message(msgid_lines=[key[1]], msgstr_lines=[
- #for lang, trans, (is_fuzzy, comments) in msg[2:]:
- #if trans and not is_fuzzy:
- #i18n_dict.setdefault(lang, dict())[key] = trans
-#
- #if key:
- #if not curr_hash:
- #import hashlib
- #curr_hash = hashlib.new(PARSER_CACHE_HASH, str(src).encode()).digest()
- #_parser_cache[key] = (curr_hash, val)
- #return ret \ No newline at end of file
+ def parse_from_py(self, src, langs=set()):
+ """
+ src must be a valid path, either a py file or a module directory (in which case all py files inside it
+ will be checked, first file macthing will win!).
+ if langs set is void, all languages found are loaded.
+ """
+ default_context = self.settings.DEFAULT_CONTEXT
+ txt = None
+ if os.path.isdir(src):
+ for root, dnames, fnames in os.walk(src):
+ for fname in fnames:
+ path = os.path.join(root, fname)
+ _1, txt, _2 = self._parser_check_file(path)
+ if txt is not None:
+ self.src[self.settings.PARSER_PY_ID] = path
+ break
+ if txt is not None:
+ break
+ elif src.endswith(".py") and os.path.isfile(src):
+ _1, txt, _2 = _check_file(src, self.settings.PARSER_PY_MARKER_BEGIN, self.settings.PARSER_PY_MARKER_END)
+ if txt is not None:
+ self.src[self.settings.PARSER_PY_ID] = src
+ if txt is None:
+ return
+ env = globals()
+ exec(txt, env)
+ if "translations_tuple" not in env:
+ return # No data...
+ msgs = env["translations_tuple"]
+ for key, (sources, gen_comments), *translations in msgs:
+ if self.settings.PARSER_TEMPLATE_ID not in self.trans:
+ self.trans[self.settings.PARSER_TEMPLATE_ID] = I18nMessages(self.settings.PARSER_TEMPLATE_ID,
+ settings=self.settings)
+ self.src[self.settings.PARSER_TEMPLATE_ID] = self.src[self.settings.PARSER_PY_ID]
+ if key in self.trans[self.settings.PARSER_TEMPLATE_ID].msgs:
+ print("ERROR! key {} is defined more than once! Skipping re-definitions!")
+ continue
+ custom_src = [c for c in sources if c.startswith("bpy.")]
+ src = [c for c in sources if not c.startswith("bpy.")]
+ common_comment_lines = [self.settings.PO_COMMENT_PREFIX_GENERATED + c for c in gen_comments] + \
+ [self.settings.PO_COMMENT_PREFIX_SOURCE_CUSTOM + c for c in custom_src] + \
+ [self.settings.PO_COMMENT_PREFIX_SOURCE + c for c in src]
+ ctxt = [key[0]] if key[0] else [default_context]
+ self.trans[self.settings.PARSER_TEMPLATE_ID].msgs[key] = I18nMessage(ctxt, [key[1]], [""],
+ common_comment_lines, False, False,
+ settings=self.settings)
+ for uid, msgstr, (is_fuzzy, user_comments) in translations:
+ if uid not in self.trans:
+ self.trans[uid] = I18nMessages(uid, settings=self.settings)
+ self.src[uid] = self.src[self.settings.PARSER_PY_ID]
+ comment_lines = [self.settings.PO_COMMENT_PREFIX + c for c in user_comments] + common_comment_lines
+ self.trans[uid].msgs[key] = I18nMessage(ctxt, [key[1]], [msgstr], comment_lines, False, is_fuzzy,
+ settings=self.settings)
+ self.unescape()
+
+ def write(self, kind, langs=set()):
+ self.writers[kind](self, langs)
+
+ def write_to_po(self, langs=set()):
+ """
+ Write all translations into po files. By default, write in the same files (or dir) as the source, specify
+ a custom self.dst function to write somewhere else!
+ Note: If langs is set and you want to export the pot template as well, langs must contain PARSER_TEMPLATE_ID
+ ({} currently).
+ """.format(self.settings.PARSER_TEMPLATE_ID)
+ keys = self.trans.keys()
+ if langs:
+ keys &= langs
+ for uid in keys:
+ dst = self.dst(self, self.src.get(uid, ""), uid, 'PO')
+ self.trans[uid].write('PO', dst)
+
+ def write_to_py(self, langs=set()):
+ """
+ Write all translations as python code, either in a "translations.py" file under same dir as source(s), or in
+ specified file is self.py_file is set (default, as usual can be customized with self.dst callable!).
+ Note: If langs is set and you want to export the pot template as well, langs must contain PARSER_TEMPLATE_ID
+ ({} currently).
+ """.format(self.settings.PARSER_TEMPLATE_ID)
+ default_context = self.settings.DEFAULT_CONTEXT
+ def _gen_py(self, langs, tab=" "):
+ _lencomm = len(self.settings.PO_COMMENT_PREFIX)
+ _lengen = len(self.settings.PO_COMMENT_PREFIX_GENERATED)
+ _lensrc = len(self.settings.PO_COMMENT_PREFIX_SOURCE)
+ _lencsrc = len(self.settings.PO_COMMENT_PREFIX_SOURCE_CUSTOM)
+ ret = [
+ "# NOTE: You can safely move around this auto-generated block (with the begin/end markers!), and "
+ "edit the translations by hand.",
+ "# Just carefully respect the format of the tuple!",
+ "",
+ "# Tuple of tuples "
+ "((msgctxt, msgid), (sources, gen_comments), (lang, translation, (is_fuzzy, comments)), ...)",
+ "translations_tuple = (",
+ ]
+ # First gather all keys (msgctxt, msgid) - theoretically, all translations should share the same, but...
+ keys = set()
+ for trans in self.trans.items:
+ keys |= trans.msgs.keys()
+ # Get the ref translation (ideally, PARSER_TEMPLATE_ID one, else the first one that pops up!
+ # Ref translation will be used to generate sources "comments"
+ ref = self.trans.get(self.settings.PARSER_TEMPLATE_ID) or self.trans[list(self.trans.keys())[0]]
+ # Get all languages (uids) and sort them (PARSER_TEMPLATE_ID excluded!)
+ translations = self.trans.keys() - {self.settings.PARSER_TEMPLATE_ID}
+ if langs:
+ translations &= langs
+ translations = [('"' + lng + '"', " " * len(lng) + 4, self.trans[lng]) for lng in sorted(translations)]
+ for key in keys:
+ if ref.msgs[key].is_commented:
+ continue
+ # Key (context + msgid).
+ msgctxt, msgid = key
+ if not msgctxt:
+ msgctxt = default_context
+ ret.append(tab + "(({}, \"{}\"),".format('"' + msgctxt + '"' if msgctxt else "None", msgid))
+ # Common comments (mostly sources!).
+ sources = []
+ gen_comments = []
+ for comment in ref.msgs[key].comment_lines:
+ if comment.startswith(self.settings.PO_COMMENT_PREFIX_SOURCE_CUSTOM):
+ sources.append(comment[_lencsrc:])
+ elif comment.startswith(self.settings.PO_COMMENT_PREFIX_SOURCE):
+ sources.append(comment[_lensrc:])
+ elif comment.startswith(self.settings.PO_COMMENT_PREFIX_GENERATED):
+ gen_comments.append(comment[_lengen:])
+ if not (sources or gen_comments):
+ ret.append(tab + " ((), ()),")
+ else:
+ if len(sources) > 1:
+ ret.append(tab + " ((\"" + sources[0] + "\",")
+ ret += [tab + " \"" + s + "\"," for s in sources[1:-1]]
+ ret.append(tab + " \"" + sources[-1] + "\"),")
+ else:
+ ret.append(tab + " ((" + ('"' + sources[0] + '",' if sources else "") + "),")
+ if len(gen_comments) > 1:
+ ret.append(tab + " (\"" + gen_comments[0] + "\",")
+ ret += [tab + " \"" + s + "\"," for s in gen_comments[1:-1]]
+ ret.append(tab + " \"" + gen_comments[-1] + "\")),")
+ else:
+ ret.append(tab + " (" + ('"' + gen_comments[0] + '",' if gen_comments else "") + ")),")
+ # All languages
+ for lngstr, lngsp, trans in translations:
+ if trans.msgs[key].is_commented:
+ continue
+ # Language code and translation.
+ ret.append(tab + " (" + lngstr + ", \"" + trans.msgs[key].msgstr + "\",")
+ # User comments and fuzzy.
+ comments = []
+ for comment in trans.msgs[key].comment_lines:
+ if comment.startswith(self.settings.PO_COMMENT_PREFIX):
+ comments.append(comment[_lencomm:])
+ ret.append(tab + lngsp + "(" + ("True" if trans.msgs[key].is_fuzzy else "False") + ",")
+ if len(comments) > 1:
+ ret.append(tab + lngsp + " (\"" + comments[0] + "\",")
+ ret += [tab + lngsp + " \"" + s + "\"," for s in comments[1:-1]]
+ ret.append(tab + lngsp + " \"" + comments[-1] + "\"))),")
+ else:
+ ret[-1] = ret[-1] + " " + ('"' + comments[0] + '",' if comments else "") + "))),"
+ ret.append(tab + "),")
+ ret += [
+ ")",
+ "",
+ "translations_dict = {}",
+ "for msg in translations_tuple:",
+ tab + "key = msg[0]",
+ tab + "for lang, trans, (is_fuzzy, comments) in msg[2:]:",
+ tab * 2 + "if trans and not is_fuzzy:",
+ tab * 3 + "translations_dict.setdefault(lang, {})[key] = trans",
+ "",
+ ]
+ return ret
+
+ self.escape(True)
+ dst = self.dst(self, self.src.get(self.settings.PARSER_PY_ID, ""), self.settings.PARSER_PY_ID, 'PY')
+ prev = txt = next = ""
+ if os.path.exists(dst):
+ if not os.path.isfile(dst):
+ print("WARNING: trying to write as python code into {}, which is not a file! Aborting.".format(dst))
+ return
+ prev, txt, next = self._parser_check_file(dst, self.settings.PARSER_MAX_FILE_SIZE,
+ self.settings.PARSER_PY_MARKER_BEGIN,
+ self.settings.PARSER_PY_MARKER_END)
+ if prev is None:
+ return
+ if txt is None:
+ print("WARNING: given python file {} has no auto-generated translations yet, will be added at "
+ "the end of the file, you can move that section later if needed...".format(dst))
+ txt = _gen_py(self, langs)
+ else:
+ printf("Creating python file {} containing translations.".format(dst))
+ txt = [
+ "# ***** BEGIN GPL LICENSE BLOCK *****",
+ "#",
+ "# This program is free software; you can redistribute it and/or",
+ "# modify it under the terms of the GNU General Public License",
+ "# as published by the Free Software Foundation; either version 2",
+ "# of the License, or (at your option) any later version.",
+ "#",
+ "# This program is distributed in the hope that it will be useful,",
+ "# but WITHOUT ANY WARRANTY; without even the implied warranty of",
+ "# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the",
+ "# GNU General Public License for more details.",
+ "#",
+ "# You should have received a copy of the GNU General Public 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 *****",
+ "",
+ self.settings.PARSER_PY_MARKER_BEGIN,
+ "",
+ ]
+ txt += _gen_py(self, langs)
+ txt += [
+ "",
+ self.settings.PARSER_PY_MARKER_END,
+ ]
+ with open(dst, 'w') as f:
+ f.write(prev + "\n".join(txt) + (next or ""))
+ self.unescape()
+
+ parsers = {
+ "PO": parse_from_po,
+ "PY": parse_from_py,
+ }
+
+ writers = {
+ "PO": write_to_po,
+ "PY": write_to_py,
+ }
diff --git a/release/scripts/modules/bpy/utils.py b/release/scripts/modules/bpy/utils.py
index 7b5de231b4b..9c4117f0953 100644
--- a/release/scripts/modules/bpy/utils.py
+++ b/release/scripts/modules/bpy/utils.py
@@ -35,6 +35,7 @@ __all__ = (
"register_module",
"register_manual_map",
"unregister_manual_map",
+ "make_rna_paths",
"manual_map",
"resource_path",
"script_path_user",
@@ -640,3 +641,29 @@ def manual_map():
continue
yield prefix, url_manual_mapping
+
+
+# Build an RNA path from struct/property/enum names.
+def make_rna_paths(struct_name, prop_name, enum_name):
+ """
+ Create RNA "paths" from given names.
+
+ :arg struct_name: Name of a RNA struct (like e.g. "Scene").
+ :type struct_name: string
+ :arg prop_name: Name of a RNA struct's property.
+ :type prop_name: string
+ :arg enum_name: Name of a RNA enum identifier.
+ :type enum_name: string
+ :return: A triple of three "RNA paths" (most_complete_path, "struct.prop", "struct.prop:'enum'").
+ If no enum_name is given, the third element will always be void.
+ :rtype: tuple of strings
+ """
+ src = src_rna = src_enum = ""
+ if struct_name:
+ if prop_name:
+ src = src_rna = ".".join((struct_name, prop_name))
+ if enum_name:
+ src = src_enum = "{}:'{}'".format(src_rna, enum_name)
+ else:
+ src = src_rna = struct_name
+ return src, src_rna, src_enum
diff --git a/release/scripts/modules/bpy_extras/keyconfig_utils.py b/release/scripts/modules/bpy_extras/keyconfig_utils.py
index dbff90c2447..29a65965c3f 100644
--- a/release/scripts/modules/bpy_extras/keyconfig_utils.py
+++ b/release/scripts/modules/bpy_extras/keyconfig_utils.py
@@ -18,6 +18,11 @@
# <pep8 compliant>
+# bpy.type.KeyMap: (km.name, km.space_type, km.region_type, [...])
+
+# ('Script', 'EMPTY', 'WINDOW', []),
+
+
KM_HIERARCHY = [
('Window', 'EMPTY', 'WINDOW', []), # file save, window change, exit
('Screen', 'EMPTY', 'WINDOW', [ # full screen, undo, screenshot
@@ -42,6 +47,7 @@ KM_HIERARCHY = [
('Vertex Paint', 'EMPTY', 'WINDOW', []),
('Weight Paint', 'EMPTY', 'WINDOW', []),
+ ('Weight Paint Vertex Selection', 'EMPTY', 'WINDOW', []),
('Face Mask', 'EMPTY', 'WINDOW', []),
('Image Paint', 'EMPTY', 'WINDOW', []), # image and view3d
('Sculpt', 'EMPTY', 'WINDOW', []),
@@ -49,9 +55,12 @@ KM_HIERARCHY = [
('Armature Sketch', 'EMPTY', 'WINDOW', []),
('Particle', 'EMPTY', 'WINDOW', []),
+ ('Knife Tool Modal Map', 'EMPTY', 'WINDOW', []),
+ ('Paint Stroke Modal', 'EMPTY', 'WINDOW', []),
+
('Object Non-modal', 'EMPTY', 'WINDOW', []), # mode change
- ('3D View Generic', 'VIEW_3D', 'WINDOW', []) # toolbar and properties
+ ('3D View Generic', 'VIEW_3D', 'WINDOW', []), # toolbar and properties
]),
('Frames', 'EMPTY', 'WINDOW', []), # frame navigation (per region)
@@ -59,53 +68,65 @@ KM_HIERARCHY = [
('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', [])
+ ('Graph Editor Generic', 'GRAPH_EDITOR', 'WINDOW', []),
]),
('Dopesheet', 'DOPESHEET_EDITOR', 'WINDOW', []),
('NLA Editor', 'NLA_EDITOR', 'WINDOW', [
('NLA Channels', 'NLA_EDITOR', 'WINDOW', []),
- ('NLA Generic', 'NLA_EDITOR', 'WINDOW', [])
+ ('NLA Generic', 'NLA_EDITOR', 'WINDOW', []),
]),
('Image', 'IMAGE_EDITOR', 'WINDOW', [
('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', [])
+ ('Image Generic', 'IMAGE_EDITOR', 'WINDOW', []),
]),
('Timeline', 'TIMELINE', 'WINDOW', []),
('Outliner', 'OUTLINER', 'WINDOW', []),
('Node Editor', 'NODE_EDITOR', 'WINDOW', [
- ('Node Generic', 'NODE_EDITOR', 'WINDOW', [])
+ ('Node Generic', 'NODE_EDITOR', 'WINDOW', []),
+ ]),
+ ('Sequencer', 'SEQUENCE_EDITOR', 'WINDOW', [
+ ('SequencerCommon', 'SEQUENCE_EDITOR', 'WINDOW', []),
+ ('SequencerPreview', 'SEQUENCE_EDITOR', 'WINDOW', []),
]),
- ('Sequencer', 'SEQUENCE_EDITOR', 'WINDOW', []),
('Logic Editor', 'LOGIC_EDITOR', 'WINDOW', []),
('File Browser', 'FILE_BROWSER', 'WINDOW', [
('File Browser Main', 'FILE_BROWSER', 'WINDOW', []),
- ('File Browser Buttons', 'FILE_BROWSER', 'WINDOW', [])
+ ('File Browser Buttons', 'FILE_BROWSER', 'WINDOW', []),
]),
+ ('Info', 'INFO', 'WINDOW', []),
+
('Property Editor', 'PROPERTIES', 'WINDOW', []), # align context menu
- ('Text', 'TEXT_EDITOR', 'WINDOW', []),
+ ('Text', 'TEXT_EDITOR', 'WINDOW', [
+ ('Text Generic', 'TEXT_EDITOR', 'WINDOW', []),
+ ]),
('Console', 'CONSOLE', 'WINDOW', []),
('Clip', 'CLIP_EDITOR', 'WINDOW', [
('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
]),
('View3D Gesture Circle', 'EMPTY', 'WINDOW', []),
+ ('Gesture Straight Line', 'EMPTY', 'WINDOW', []),
+ ('Gesture Zoom Border', 'EMPTY', 'WINDOW', []),
('Gesture Border', 'EMPTY', 'WINDOW', []),
+
('Standard Modal Map', 'EMPTY', 'WINDOW', []),
('Transform Modal Map', 'EMPTY', 'WINDOW', []),
('View3D Fly Modal', 'EMPTY', 'WINDOW', []),
('View3D Rotate Modal', 'EMPTY', 'WINDOW', []),
('View3D Move Modal', 'EMPTY', 'WINDOW', []),
('View3D Zoom Modal', 'EMPTY', 'WINDOW', []),
+ ('View3D Dolly Modal', 'EMPTY', 'WINDOW', []),
]
diff --git a/release/scripts/modules/console/intellisense.py b/release/scripts/modules/console/intellisense.py
index a177b305fda..b694cceafea 100644
--- a/release/scripts/modules/console/intellisense.py
+++ b/release/scripts/modules/console/intellisense.py
@@ -148,7 +148,7 @@ def expand(line, cursor, namespace, private=True):
if prefix:
line = line[:cursor] + prefix + line[cursor:]
- cursor += len(prefix)
+ cursor += len(prefix.encode('utf-8'))
if no_calltip and prefix.endswith('('):
return expand(line, cursor, namespace, private)
return line, cursor, scrollback
diff --git a/release/scripts/presets/operator/wm.collada_export/second_life_rigged.py b/release/scripts/presets/operator/wm.collada_export/second_life_rigged.py
index 81769a82728..717e044ccd6 100644
--- a/release/scripts/presets/operator/wm.collada_export/second_life_rigged.py
+++ b/release/scripts/presets/operator/wm.collada_export/second_life_rigged.py
@@ -12,6 +12,7 @@ op.deform_bones_only = True
op.active_uv_only = True
op.include_uv_textures = True
op.use_texture_copies = True
+op.triangulate = True
op.use_object_instantiation = False
op.sort_by_name = True
op.second_life = True
diff --git a/release/scripts/presets/operator/wm.collada_export/second_life_static.py b/release/scripts/presets/operator/wm.collada_export/second_life_static.py
index ad06909a276..9518fe5fb35 100644
--- a/release/scripts/presets/operator/wm.collada_export/second_life_static.py
+++ b/release/scripts/presets/operator/wm.collada_export/second_life_static.py
@@ -12,6 +12,7 @@ op.deform_bones_only = False
op.active_uv_only = True
op.include_uv_textures = True
op.use_texture_copies = True
+op.triangulate = True
op.use_object_instantiation = False
op.sort_by_name = True
op.second_life = False
diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py
index 567ea830409..f8eb55db42e 100644
--- a/release/scripts/startup/bl_operators/object.py
+++ b/release/scripts/startup/bl_operators/object.py
@@ -381,11 +381,8 @@ class ShapeTransfer(Operator):
(orig_shape_coords[i] - orig_coords[i]))
elif mode == 'RELATIVE_FACE':
- loops_vidxs = me.loops.foreach_get("vert_index")
for poly in me.polygons:
- l_start = l_stop = poly.loop_start
- l_stop += poly.loop_total
- idxs = loops_vidxs[l_start:l_stop]
+ idxs = poly.vertices[:]
v_before = idxs[-2]
v = idxs[-1]
for v_after in idxs:
diff --git a/release/scripts/startup/bl_operators/rigidbody.py b/release/scripts/startup/bl_operators/rigidbody.py
index 2a19e222796..f327c602fb6 100644
--- a/release/scripts/startup/bl_operators/rigidbody.py
+++ b/release/scripts/startup/bl_operators/rigidbody.py
@@ -216,8 +216,8 @@ class ConnectRigidBodies(Operator):
connection_pattern = EnumProperty(
name="Connection Pattern",
description="Pattern used to connect objects",
- items=(('SELECTED_TO_ACTIVE', "Selected to Active", "Connects selected objects to the active object"),
- ('CHAIN_DISTANCE', "Chain by Distance", "Connects objects as a chain based on distance, starting at the active object")),
+ items=(('SELECTED_TO_ACTIVE', "Selected to Active", "Connect selected objects to the active object"),
+ ('CHAIN_DISTANCE', "Chain by Distance", "Connect objects as a chain based on distance, starting at the active object")),
default='SELECTED_TO_ACTIVE',)
@classmethod
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 6ac61a9f5e7..b2f094e7ccc 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -820,25 +820,42 @@ def _wm_doc_get_id(doc_id, do_url=True, url_prefix=""):
elif len(id_split) == 2: # rna, class.prop
class_name, class_prop = id_split
+ # an operator (common case - just button referencing an op)
if hasattr(bpy.types, class_name.upper() + "_OT_" + class_prop):
if do_url:
url = ("%s/bpy.ops.%s.html#bpy.ops.%s.%s" % (url_prefix, class_name, class_name, class_prop))
else:
rna = "bpy.ops.%s.%s" % (class_name, class_prop)
else:
+ rna_class = getattr(bpy.types, class_name)
+
+ # an operator setting (selected from a running operator), rare case
+ # note: Py defined operators are subclass of Operator,
+ # C defined operators are subclass of OperatorProperties.
+ # we may need to check on this at some point.
+ if issubclass(rna_class, (bpy.types.Operator, bpy.types.OperatorProperties)):
+ # note: ignore the prop name since we don't have a way to link into it
+ class_name, class_prop = class_name.split("_OT_", 1)
+ class_name = class_name.lower()
+ if do_url:
+ url = ("%s/bpy.ops.%s.html#bpy.ops.%s.%s" % (url_prefix, class_name, class_name, class_prop))
+ else:
+ rna = "bpy.ops.%s.%s" % (class_name, class_prop)
+ else:
+ # an RNA setting, common case
- # detect if this is a inherited member and use that name instead
- rna_parent = getattr(bpy.types, class_name).bl_rna
- rna_prop = rna_parent.properties[class_prop]
- rna_parent = rna_parent.base
- while rna_parent and rna_prop == rna_parent.properties.get(class_prop):
- class_name = rna_parent.identifier
+ # detect if this is a inherited member and use that name instead
+ rna_parent = rna_class.bl_rna
+ rna_prop = rna_parent.properties[class_prop]
rna_parent = rna_parent.base
+ while rna_parent and rna_prop == rna_parent.properties.get(class_prop):
+ class_name = rna_parent.identifier
+ rna_parent = rna_parent.base
- if do_url:
- url = ("%s/bpy.types.%s.html#bpy.types.%s.%s" % (url_prefix, class_name, class_name, class_prop))
- else:
- rna = ("bpy.types.%s.%s" % (class_name, class_prop))
+ if do_url:
+ url = ("%s/bpy.types.%s.html#bpy.types.%s.%s" % (url_prefix, class_name, class_name, class_prop))
+ else:
+ rna = ("bpy.types.%s.%s" % (class_name, class_prop))
return url if do_url else rna
diff --git a/release/scripts/startup/bl_ui/properties_object_constraint.py b/release/scripts/startup/bl_ui/properties_object_constraint.py
index 6478e49f464..f1bad2257c0 100644
--- a/release/scripts/startup/bl_ui/properties_object_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_object_constraint.py
@@ -836,7 +836,7 @@ class ConstraintButtonsPanel():
layout.operator("clip.constraint_to_fcurve")
def SCRIPT(self, context, layout, con):
- layout.label("Blender 2.6 doesn't support python constraints yet.")
+ layout.label("Blender 2.6 doesn't support python constraints yet")
class OBJECT_PT_constraints(ConstraintButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py
index 2164b86f486..696e895fa67 100644
--- a/release/scripts/startup/bl_ui/properties_physics_fluid.py
+++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py
@@ -92,8 +92,9 @@ class PHYSICS_PT_fluid(PhysicButtonsPanel, Panel):
col = split.column()
col.label()
- col.prop(fluid, "use_speed_vectors")
- col.prop(fluid, "use_reverse_frames")
+ sub = col.column(align=True)
+ sub.prop(fluid, "use_speed_vectors")
+ sub.prop(fluid, "use_reverse_frames")
col.prop(fluid, "frame_offset", text="Offset")
layout.prop(fluid, "filepath", text="")
@@ -295,9 +296,9 @@ class PHYSICS_PT_domain_particles(PhysicButtonsPanel, Panel):
fluid = context.fluid.settings
- col = layout.column(align=True)
- col.prop(fluid, "tracer_particles")
- col.prop(fluid, "generate_particles")
+ row = layout.row()
+ row.prop(fluid, "tracer_particles", text="Tracer")
+ row.prop(fluid, "generate_particles", text="Generate")
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py
index 519f9ca47fa..eed8c84a389 100644
--- a/release/scripts/startup/bl_ui/properties_scene.py
+++ b/release/scripts/startup/bl_ui/properties_scene.py
@@ -77,10 +77,10 @@ class SCENE_PT_unit(SceneButtonsPanel, Panel):
col.row().prop(unit, "system", expand=True)
col.row().prop(unit, "system_rotation", expand=True)
- row = layout.row()
- row.active = (unit.system != 'NONE')
- row.prop(unit, "scale_length", text="Scale")
- row.prop(unit, "use_separate")
+ if unit.system != 'NONE':
+ row = layout.row()
+ row.prop(unit, "scale_length", text="Scale")
+ row.prop(unit, "use_separate")
class SCENE_PT_keying_sets(SceneButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index e32db805a29..14fbbe15cfd 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -332,8 +332,7 @@ class CLIP_PT_tools_solve(CLIP_PT_tracking_panel, Panel):
col.prop(tracking_object, "keyframe_b")
col = layout.column(align=True)
- col.active = (tracking_object.is_camera and
- not settings.use_tripod_solver)
+ col.active = tracking_object.is_camera
col.label(text="Refine:")
col.prop(settings, "refine_intrinsics", text="")
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 7841acf01b3..aa445b9500d 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -89,6 +89,7 @@ class SEQUENCER_HT_header(Header):
layout.separator()
layout.operator("sequencer.refresh_all")
+ layout.prop(st, "preview_channels", expand=True, text="")
layout.prop(st, "display_channel", text="Channel")
ed = context.scene.sequence_editor
diff --git a/release/scripts/startup/bl_ui/space_userpref_keymap.py b/release/scripts/startup/bl_ui/space_userpref_keymap.py
index e9eb2aa8b8f..0842a90762c 100644
--- a/release/scripts/startup/bl_ui/space_userpref_keymap.py
+++ b/release/scripts/startup/bl_ui/space_userpref_keymap.py
@@ -213,14 +213,97 @@ class InputKeyMapPanel:
self.draw_km(display_keymaps, kc, kmm, None, layout, level + 1)
layout.context_pointer_set("keymap", km)
- def draw_filtered(self, display_keymaps, filter_text, layout):
+ _EVENT_TYPES = set()
+ _EVENT_TYPE_MAP = {}
+ def draw_filtered(self, display_keymaps, filter_type, filter_text, layout):
+
+ if filter_type == 'NAME':
+ def filter_func(kmi):
+ return (filter_text in kmi.idname.lower() or
+ filter_text in kmi.name.lower())
+
+ else:
+ if not self._EVENT_TYPES:
+ enum = bpy.types.Event.bl_rna.properties["type"].enum_items
+ self._EVENT_TYPES.update(enum.keys())
+ self._EVENT_TYPE_MAP.update({item.name.replace(" ", "_").upper(): key for key, item in enum.items()})
+
+ del enum
+ self._EVENT_TYPE_MAP.update({
+ "*": 'NUMPAD_ASTERIX',
+ "/": 'NUMPAD_SLASH',
+ "RMB": 'RIGHTMOUSE',
+ "LMB": 'LEFTMOUSE',
+ "MMB": 'MIDDLEMOUSE',
+ })
+ # done with once off init
+
+ filter_text_split = filter_text.strip()
+ filter_text_split = filter_text.split()
+
+ # Modifier {kmi.attribute: name} mapping
+ key_mod = {
+ "ctrl": "ctrl",
+ "alt": "alt",
+ "shift": "shift",
+ "cmd": "oskey",
+ "oskey": "oskey",
+ "any": "any",
+ }
+ # KeyMapItem like dict, use for comparing against
+ # attr: state
+ kmi_test_dict = {}
+
+ # initialize? - so if a if a kmi has a MOD assigned it wont show up.
+ #~ for kv in key_mod.values():
+ #~ kmi_test_dict[kv] = False
+
+ # altname: attr
+ for kk, kv in key_mod.items():
+ if kk in filter_text_split:
+ filter_text_split.remove(kk)
+ kmi_test_dict[kv] = True
+ # whats left should be the event type
+ if len(filter_text_split) > 1:
+ return False
+ elif filter_text_split:
+ kmi_type = filter_text_split[0].upper()
+
+ if kmi_type not in self._EVENT_TYPES:
+ # replacement table
+ kmi_type_test = self._EVENT_TYPE_MAP.get(kmi_type)
+ if kmi_type_test is None:
+ # print("Unknown Type:", kmi_type)
+
+ # Partial match
+ for k, v in self._EVENT_TYPE_MAP.items():
+ if kmi_type in k:
+ kmi_type_test = v
+ break
+ if kmi_type in v:
+ kmi_type_test = v
+ break
+
+ if kmi_type_test is None:
+ return False
+
+ kmi_type = kmi_type_test
+ del kmi_type_test
+
+ kmi_test_dict["type"] = kmi_type
+
+ # main filter func, runs many times
+ def filter_func(kmi):
+ for kk, ki in kmi_test_dict.items():
+ if getattr(kmi, kk) != ki:
+ return False
+ return True
+
for km, kc in display_keymaps:
km = km.active()
layout.context_pointer_set("keymap", km)
- filtered_items = [kmi for kmi in km.keymap_items
- if (filter_text in kmi.idname.lower() or
- filter_text in kmi.name.lower())]
+ filtered_items = [kmi for kmi in km.keymap_items if filter_func(kmi)]
if filtered_items:
col = layout.column()
@@ -243,6 +326,7 @@ class InputKeyMapPanel:
col = self.indented_layout(layout, 1)
subcol = col.split(percentage=0.2).column()
subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN')
+ return True
def draw_hierarchy(self, display_keymaps, layout):
from bpy_extras import keyconfig_utils
@@ -254,6 +338,7 @@ class InputKeyMapPanel:
wm = context.window_manager
kc = wm.keyconfigs.user
+ spref = context.space_data
col = layout.column()
sub = col.column()
@@ -264,7 +349,7 @@ class InputKeyMapPanel:
row = subcol.row(align=True)
#~ row.prop_search(wm.keyconfigs, "active", wm, "keyconfigs", text="Key Config:")
- text = bpy.path.display_name(context.window_manager.keyconfigs.active.name)
+ text = bpy.path.display_name(wm.keyconfigs.active.name)
if not text:
text = "Blender (default)"
row.menu("USERPREF_MT_keyconfigs", text=text)
@@ -273,17 +358,27 @@ class InputKeyMapPanel:
#~ layout.context_pointer_set("keyconfig", wm.keyconfigs.active)
#~ row.operator("wm.keyconfig_remove", text="", icon='X')
-
- row.prop(context.space_data, "filter_text", icon='VIEWZOOM')
+ row.separator()
+ rowsub = row.split(align=True, percentage=0.33)
+ # postpone drawing into rowsub, so we can set alert!
col.separator()
-
display_keymaps = keyconfig_utils.keyconfig_merge(kc, kc)
- if context.space_data.filter_text != "":
- filter_text = context.space_data.filter_text.lower()
- self.draw_filtered(display_keymaps, filter_text, col)
+ filter_type = spref.filter_type
+ filter_text = spref.filter_text
+ if filter_text != "":
+ filter_text = filter_text.lower()
+ ok = self.draw_filtered(display_keymaps, filter_type, filter_text, col)
else:
self.draw_hierarchy(display_keymaps, col)
+ ok = True
+
+ # go back and fill in rowsub
+ rowsub.prop(spref, "filter_type", text="")
+ rowsubsub = rowsub.row(align=True)
+ if not ok:
+ rowsubsub.alert = True
+ rowsubsub.prop(spref, "filter_text", text="", icon='VIEWZOOM')
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index aafa4f1fe06..a8be8b21498 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -44,7 +44,13 @@ class VIEW3D_HT_header(Header):
sub.menu("VIEW3D_MT_view")
# Select Menu
- if mode_string not in {'EDIT_TEXT', 'SCULPT', 'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}:
+ if mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}:
+ mesh = obj.data
+ if mesh.use_paint_mask:
+ sub.menu("VIEW3D_MT_select_paint_mask")
+ elif mesh.use_paint_mask_vertex and mode_string == 'PAINT_WEIGHT':
+ sub.menu("VIEW3D_MT_select_paint_mask_vertex")
+ elif mode_string not in {'EDIT_TEXT', 'SCULPT'}:
sub.menu("VIEW3D_MT_select_%s" % mode_string.lower())
if edit_object:
@@ -203,7 +209,7 @@ class VIEW3D_MT_transform_object(VIEW3D_MT_transform_base):
layout.operator("object.origin_set", text="Geometry to Origin").type = 'GEOMETRY_ORIGIN'
layout.operator("object.origin_set", text="Origin to Geometry").type = 'ORIGIN_GEOMETRY'
layout.operator("object.origin_set", text="Origin to 3D Cursor").type = 'ORIGIN_CURSOR'
-
+ layout.operator("object.origin_set", text="Origin to Center of Mass").type = 'ORIGIN_CENTER_OF_MASS'
layout.separator()
layout.operator("object.randomize_transform")
@@ -623,7 +629,7 @@ class VIEW3D_MT_select_edit_curve(Menu):
layout.operator("curve.select_all").action = 'TOGGLE'
layout.operator("curve.select_all", text="Inverse").action = 'INVERT'
layout.operator("curve.select_random")
- layout.operator("curve.select_nth", text="Every Nth Number of Points")
+ layout.operator("curve.select_nth")
layout.operator("curve.select_linked", text="Select Linked")
layout.separator()
@@ -653,7 +659,7 @@ class VIEW3D_MT_select_edit_surface(Menu):
layout.operator("curve.select_all").action = 'TOGGLE'
layout.operator("curve.select_all", text="Inverse").action = 'INVERT'
layout.operator("curve.select_random")
- layout.operator("curve.select_nth", text="Every Nth Number of Points")
+ layout.operator("curve.select_nth")
layout.operator("curve.select_linked", text="Select Linked")
layout.separator()
@@ -673,6 +679,7 @@ class VIEW3D_MT_select_edit_metaball(Menu):
layout = self.layout
layout.operator("view3d.select_border")
+ layout.operator("view3d.select_circle")
layout.separator()
@@ -730,15 +737,39 @@ class VIEW3D_MT_select_edit_armature(Menu):
layout.operator("object.select_pattern", text="Select Pattern...")
-class VIEW3D_MT_select_face(Menu): # XXX no matching enum
+class VIEW3D_MT_select_paint_mask(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("paint.face_select_all").action = 'TOGGLE'
+ layout.operator("paint.face_select_all", text="Inverse").action = 'INVERT'
+
+ layout.separator()
+
+ layout.operator("paint.face_select_linked", text="Linked")
+
+
+class VIEW3D_MT_select_paint_mask_vertex(Menu):
bl_label = "Select"
def draw(self, context):
- # layout = self.layout
+ layout = self.layout
+
+ layout.operator("view3d.select_border")
+ layout.operator("view3d.select_circle")
+
+ layout.separator()
+
+ layout.operator("paint.vert_select_all").action = 'TOGGLE'
+ layout.operator("paint.vert_select_all", text="Inverse").action = 'INVERT'
- # TODO
- # see view3d_select_faceselmenu
- pass
# ********** Object menu **********
@@ -1612,6 +1643,8 @@ class BoneOptions:
def draw(self, context):
layout = self.layout
+ default_context = bpy.app.translations.contexts.default
+
options = [
"show_wire",
"use_deform",
@@ -1631,7 +1664,8 @@ class BoneOptions:
opt_suffix = "bone."
for opt in options:
- props = layout.operator("wm.context_collection_boolean_set", text=bone_props[opt].name)
+ props = layout.operator("wm.context_collection_boolean_set", text=bone_props[opt].name,
+ text_ctxt=default_context)
props.data_path_iter = data_path_iter
props.data_path_item = opt_suffix + opt
props.type = self.type
@@ -2497,25 +2531,37 @@ class VIEW3D_PT_view3d_meshdisplay(Panel):
mesh = context.active_object.data
- col = layout.column()
+ split = layout.split()
+
+ col = split.column()
col.label(text="Overlays:")
- col.prop(mesh, "show_edges", text="Edges")
col.prop(mesh, "show_faces", text="Faces")
+ col.prop(mesh, "show_edges", text="Edges")
col.prop(mesh, "show_edge_crease", text="Creases")
- col.prop(mesh, "show_edge_bevel_weight", text="Bevel Weights")
+
+ col = split.column()
+ col.label()
col.prop(mesh, "show_edge_seams", text="Seams")
col.prop(mesh, "show_edge_sharp", text="Sharp")
+ col.prop(mesh, "show_edge_bevel_weight", text="Weights")
+
if context.scene and bpy.app.build_options.freestyle:
col.prop(mesh, "show_freestyle_edge_marks", text="Freestyle Edge Marks")
col.prop(mesh, "show_freestyle_face_marks", text="Freestyle Face Marks")
+
+ col = layout.column()
col.separator()
col.label(text="Normals:")
row = col.row()
+
sub = row.row(align=True)
sub.prop(mesh, "show_normal_vertex", text="", icon='VERTEXSEL')
sub.prop(mesh, "show_normal_face", text="", icon='FACESEL')
- row.prop(context.scene.tool_settings, "normal_size", text="Size")
+
+ sub = row.row(align=True)
+ sub.active = mesh.show_normal_vertex or mesh.show_normal_face
+ sub.prop(context.scene.tool_settings, "normal_size", text="Size")
col.separator()
col.label(text="Numerics:")
diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h
index 4cdfc1cba95..6baf20aeb2c 100644
--- a/source/blender/blenkernel/BKE_depsgraph.h
+++ b/source/blender/blenkernel/BKE_depsgraph.h
@@ -30,114 +30,94 @@
* \ingroup bke
*/
+/* Dependency Graph
+ *
+ * The dependency graph tracks relations between datablocks, and is used to
+ * determine which datablocks need to be update based on dependencies and
+ * visibility.
+ *
+ * It does not itself execute changes in objects, but rather sorts the objects
+ * in the appropriate order and sets flags indicating they should be updated.
+ */
+
#ifdef __cplusplus
extern "C" {
#endif
-// #define DEPS_DEBUG
-
-struct DagForest;
-struct DagNode;
-struct DagNodeQueue;
-struct GHash;
struct ID;
struct Main;
struct Object;
struct Scene;
-/* **** DAG relation types *** */
-
-/* scene link to object */
-#define DAG_RL_SCENE (1 << 0)
-/* object link to data */
-#define DAG_RL_DATA (1 << 1)
-
-/* object changes object (parent, track, constraints) */
-#define DAG_RL_OB_OB (1 << 2)
-/* object changes obdata (hooks, constraints) */
-#define DAG_RL_OB_DATA (1 << 3)
-/* data changes object (vertex parent) */
-#define DAG_RL_DATA_OB (1 << 4)
-/* data changes data (deformers) */
-#define DAG_RL_DATA_DATA (1 << 5)
-
-#define DAG_NO_RELATION (1 << 6)
-
-#define DAG_RL_ALL_BUT_DATA (DAG_RL_SCENE | DAG_RL_OB_OB | DAG_RL_OB_DATA | DAG_RL_DATA_OB | DAG_RL_DATA_DATA)
-#define DAG_RL_ALL (DAG_RL_ALL_BUT_DATA | DAG_RL_DATA)
-
-
-typedef void (*graph_action_func)(void *ob, void **data);
-
-// queues are returned by all BFS & DFS queries
-// opaque type
-void *pop_ob_queue(struct DagNodeQueue *queue);
-int queue_count(struct DagNodeQueue *queue);
-void queue_delete(struct DagNodeQueue *queue);
-
-// queries
-struct DagForest *build_dag(struct Main *bmain, struct Scene *sce, short mask);
-void free_forest(struct DagForest *Dag);
-
-// note :
-// the meanings of the 2 returning values is a bit different :
-// BFS return 1 for cross-edges and back-edges. the latter are considered harmfull, not the former
-// DFS return 1 only for back-edges
-int pre_and_post_BFS(struct DagForest *dag, short mask, graph_action_func pre_func, graph_action_func post_func, void **data);
-int pre_and_post_DFS(struct DagForest *dag, short mask, graph_action_func pre_func, graph_action_func post_func, void **data);
-
-int pre_and_post_source_BFS(struct DagForest *dag, short mask, struct DagNode *source, graph_action_func pre_func, graph_action_func post_func, void **data);
-int pre_and_post_source_DFS(struct DagForest *dag, short mask, struct DagNode *source, graph_action_func pre_func, graph_action_func post_func, void **data);
-
-struct DagNodeQueue *get_obparents(struct DagForest *dag, void *ob);
-struct DagNodeQueue *get_first_ancestors(struct DagForest *dag, void *ob);
-struct DagNodeQueue *get_all_childs(struct DagForest *dag, void *ob);
-short are_obs_related(struct DagForest *dag, void *ob1, void *ob2);
-int is_acyclic(struct DagForest *dag);
-//int get_cycles(struct DagForest *dag, struct DagNodeQueue **queues, int *count); //
-
-/* ********** API *************** */
-/* Note that the DAG never executes changes in Objects, only sets flags in Objects */
-
-/* clear all dependency graphs, call this when changing relations between objects.
- * the dependency graphs will be rebuilt just before they are used to avoid them
- * getting rebuild many times during operators */
-void DAG_relations_tag_update(struct Main *bmain);
-
-/* (re)-create the dependency graph before using it */
-void DAG_scene_relations_update(struct Main *bmain, struct Scene *sce);
-
-/* force an immediate rebuild of the dependency graph, only needed in rare cases */
-void DAG_scene_relations_rebuild(struct Main *bmain, struct Scene *scene);
-
-/* flag all objects that need recalc because they're animated */
-void DAG_scene_update_flags(struct Main *bmain, struct Scene *sce, unsigned int lay, const short do_time);
-/* flushes all recalc flags in objects down the dependency tree */
-void DAG_scene_flush_update(struct Main *bmain, struct Scene *sce, unsigned int lay, const short do_time);
-/* tag objects for update on file load */
-void DAG_on_visible_update(struct Main *bmain, const short do_time);
-
-/* tag datablock to get updated for the next redraw */
-void DAG_id_tag_update_ex(struct Main *bmain, struct ID *id, short flag);
-void DAG_id_tag_update(struct ID *id, short flag);
-/* flush all tagged updates */
-void DAG_ids_flush_tagged(struct Main *bmain);
-/* check and clear ID recalc flags */
-void DAG_ids_check_recalc(struct Main *bmain, struct Scene *scene, int time);
-void DAG_ids_clear_recalc(struct Main *bmain);
-/* test if any of this id type is tagged for update */
-void DAG_id_type_tag(struct Main *bmain, short idtype);
-int DAG_id_type_tagged(struct Main *bmain, short idtype);
-
-/* (re)-create dependency graph for armature pose */
-void DAG_pose_sort(struct Object *ob);
-
-/* callback for editors module to do updates */
-void DAG_editors_update_cb(void (*id_func)(struct Main *bmain, struct ID *id),
- void (*scene_func)(struct Main *bmain, struct Scene *scene, int updated));
-
-/* debugging */
-void DAG_print_dependencies(struct Main *bmain, struct Scene *scene, struct Object *ob);
+/* Build and Update
+ *
+ * DAG_scene_relations_update will rebuild the dependency graph for a given
+ * scene if needed, and sort objects in the scene.
+ *
+ * DAG_relations_tag_update will clear all dependency graphs and mark them to
+ * be rebuilt later. The graph is not rebuilt immediately to avoid slowdowns
+ * when this function is call multiple times from different operators.
+ *
+ * DAG_scene_relations_rebuild forces an immediaterebuild of the dependency
+ * graph, this is only needed in rare cases
+ */
+
+void DAG_scene_relations_update(struct Main *bmain, struct Scene *sce);
+void DAG_relations_tag_update(struct Main *bmain);
+void DAG_scene_relations_rebuild(struct Main *bmain, struct Scene *scene);
+void DAG_scene_free(struct Scene *sce);
+
+/* Update Tagging
+ *
+ * DAG_scene_update_flags will mark all objects that depend on time (animation,
+ * physics, ..) to be recalculated, used when changing the current frame.
+ *
+ * DAG_on_visible_update will mark all objects that are visible for the first
+ * time to be updated, for example on file load or changing layer visibility.
+ *
+ * DAG_id_tag_update will mark a given datablock to be updated. The flag indicates
+ * a specific subset to be update (only object transform and data for now).
+ *
+ * DAG_id_type_tag marks a particular datablock type as having changing. This does
+ * not cause any updates but is used by external render engines to detect if for
+ * example a datablock was removed. */
+
+void DAG_scene_update_flags(struct Main *bmain, struct Scene *sce, unsigned int lay, const short do_time);
+void DAG_on_visible_update(struct Main *bmain, const short do_time);
+
+void DAG_id_tag_update(struct ID *id, short flag);
+void DAG_id_tag_update_ex(struct Main *bmain, struct ID *id, short flag);
+void DAG_id_type_tag(struct Main *bmain, short idtype);
+int DAG_id_type_tagged(struct Main *bmain, short idtype);
+
+/* Flushing Tags
+ *
+ * DAG_scene_flush_update flushes object recalculation flags immediately to other
+ * dependencies. Do not use outside of depsgraph.c, this will be removed.
+ *
+ * DAG_ids_flush_tagged will flush datablock update flags flags to dependencies,
+ * use this right before updating to mark all the needed datablocks for update.
+ *
+ * DAG_ids_check_recalc and DAG_ids_clear_recalc are used for external render
+ * engines to detect changes. */
+
+void DAG_scene_flush_update(struct Main *bmain, struct Scene *sce, unsigned int lay, const short do_time);
+void DAG_ids_flush_tagged(struct Main *bmain);
+void DAG_ids_check_recalc(struct Main *bmain, struct Scene *scene, int time);
+void DAG_ids_clear_recalc(struct Main *bmain);
+
+/* Armature: sorts the bones according to dependencies between them */
+
+void DAG_pose_sort(struct Object *ob);
+
+/* Editors: callbacks to notify editors of datablock changes */
+
+void DAG_editors_update_cb(void (*id_func)(struct Main *bmain, struct ID *id),
+ void (*scene_func)(struct Main *bmain, struct Scene *scene, int updated));
+
+/* Debugging: print dependency graph for scene or armature object to console */
+
+void DAG_print_dependencies(struct Main *bmain, struct Scene *scene, struct Object *ob);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_report.h b/source/blender/blenkernel/BKE_report.h
index e659954a3ac..4dc16f6266f 100644
--- a/source/blender/blenkernel/BKE_report.h
+++ b/source/blender/blenkernel/BKE_report.h
@@ -34,6 +34,8 @@
extern "C" {
#endif
+#include <stdio.h>
+
#include "DNA_windowmanager_types.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index 12779a697b6..bab961bcbd2 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -91,6 +91,7 @@ void BKE_rigidbody_remove_constraint(struct Scene *scene, struct Object *ob);
void BKE_rigidbody_aftertrans_update(struct Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle);
void BKE_rigidbody_sync_transforms(struct RigidBodyWorld *rbw, struct Object *ob, float ctime);
void BKE_rigidbody_cache_reset(struct RigidBodyWorld *rbw);
+void BKE_rigidbody_rebuild_world(struct Scene *scene, float ctime);
void BKE_rigidbody_do_simulation(struct Scene *scene, float ctime);
#endif /* __BKE_RIGIDBODY_H__ */
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index eef134a6872..c0ff634671d 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -36,6 +36,7 @@ struct Editing;
struct ImBuf;
struct Main;
struct Mask;
+struct MovieClip;
struct Scene;
struct Sequence;
struct SequenceModifierData;
@@ -322,6 +323,8 @@ void BKE_sequence_base_dupli_recursive(struct Scene *scene, struct Scene *scene_
int BKE_sequence_is_valid_check(struct Sequence *seq);
void BKE_sequencer_clear_scene_in_allseqs(struct Main *bmain, struct Scene *sce);
+void BKE_sequencer_clear_movieclip_in_clipboard(struct MovieClip *clip);
+void BKE_sequencer_clear_mask_in_clipboard(struct Mask *mask);
struct Sequence *BKE_sequence_get_by_name(struct ListBase *seqbase, const char *name, int recursive);
diff --git a/source/blender/blenkernel/depsgraph_private.h b/source/blender/blenkernel/depsgraph_private.h
index 12c111f5f16..ad5369c0820 100644
--- a/source/blender/blenkernel/depsgraph_private.h
+++ b/source/blender/blenkernel/depsgraph_private.h
@@ -34,9 +34,27 @@
#include "DNA_constraint_types.h"
#include "BKE_constraint.h"
+/* **** DAG relation types *** */
+
+/* scene link to object */
+#define DAG_RL_SCENE (1 << 0)
+/* object link to data */
+#define DAG_RL_DATA (1 << 1)
+
+/* object changes object (parent, track, constraints) */
+#define DAG_RL_OB_OB (1 << 2)
+/* object changes obdata (hooks, constraints) */
+#define DAG_RL_OB_DATA (1 << 3)
+/* data changes object (vertex parent) */
+#define DAG_RL_DATA_OB (1 << 4)
+/* data changes data (deformers) */
+#define DAG_RL_DATA_DATA (1 << 5)
+
+#define DAG_NO_RELATION (1 << 6)
+
+#define DAG_RL_ALL_BUT_DATA (DAG_RL_SCENE | DAG_RL_OB_OB | DAG_RL_OB_DATA | DAG_RL_DATA_OB | DAG_RL_DATA_DATA)
+#define DAG_RL_ALL (DAG_RL_ALL_BUT_DATA | DAG_RL_DATA)
-#define DEPSX 5.0f
-#define DEPSY 1.8f
#define DAGQUEUEALLOC 50
@@ -46,8 +64,6 @@ enum {
DAG_BLACK = 2
};
-
-
typedef struct DagAdjList {
struct DagNode *node;
short type;
@@ -108,11 +124,13 @@ void push_queue(DagNodeQueue *queue, DagNode *node);
void push_stack(DagNodeQueue *queue, DagNode *node);
DagNode *pop_queue(DagNodeQueue *queue);
DagNode *get_top_node_queue(DagNodeQueue *queue);
+int queue_count(DagNodeQueue *queue);
+void queue_delete(DagNodeQueue *queue);
// Dag management
-DagForest *getMainDag(void);
-void setMainDag(DagForest *dag);
DagForest *dag_init(void);
+DagForest *build_dag(struct Main *bmain, struct Scene *sce, short mask);
+void free_forest(struct DagForest *Dag);
DagNode *dag_find_node(DagForest *forest, void *fob);
DagNode *dag_add_node(DagForest *forest, void *fob);
DagNode *dag_get_node(DagForest *forest, void *fob);
@@ -126,6 +144,6 @@ DagNodeQueue *graph_dfs(void);
void set_node_xy(DagNode *node, float x, float y);
void graph_print_queue(DagNodeQueue *nqueue);
void graph_print_queue_dist(DagNodeQueue *nqueue);
-void graph_print_adj_list(void);
+void graph_print_adj_list(DagForest *dag);
#endif /* __DEPSGRAPH_PRIVATE_H__ */
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 6b3c95a5cd3..ffd86ea9ce0 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -491,7 +491,7 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob)
CustomData_copy(&dm->edgeData, &tmp.edata, CD_MASK_MESH, CD_DUPLICATE, totedge);
CustomData_copy(&dm->loopData, &tmp.ldata, CD_MASK_MESH, CD_DUPLICATE, totloop);
CustomData_copy(&dm->polyData, &tmp.pdata, CD_MASK_MESH, CD_DUPLICATE, totpoly);
- me->cd_flag = dm->cd_flag;
+ tmp.cd_flag = dm->cd_flag;
if (CustomData_has_layer(&dm->vertData, CD_SHAPEKEY)) {
KeyBlock *kb;
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 8c55ad02dc6..b919b9ffd8f 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -278,22 +278,11 @@ DagNode *pop_queue(DagNodeQueue *queue)
}
}
-void *pop_ob_queue(struct DagNodeQueue *queue)
-{
- return(pop_queue(queue)->ob);
-}
-
DagNode *get_top_node_queue(DagNodeQueue *queue)
{
return queue->first->node;
}
-int queue_count(struct DagNodeQueue *queue)
-{
- return queue->count;
-}
-
-
DagForest *dag_init(void)
{
DagForest *forest;
@@ -1190,539 +1179,6 @@ static void dag_check_cycle(DagForest *dag)
}
}
-/*
- * MainDAG is the DAG of all objects in current scene
- * used only for drawing there is one also in each scene
- */
-static DagForest *MainDag = NULL;
-
-DagForest *getMainDag(void)
-{
- return MainDag;
-}
-
-
-void setMainDag(DagForest *dag)
-{
- MainDag = dag;
-}
-
-
-/*
- * note for BFS/DFS
- * in theory we should sweep the whole array
- * but in our case the first node is the scene
- * and is linked to every other object
- *
- * for general case we will need to add outer loop
- */
-
-/*
- * ToDo : change pos kludge
- */
-
-/* adjust levels for drawing in oops space */
-void graph_bfs(void)
-{
- DagNode *node;
- DagNodeQueue *nqueue;
- int pos[50];
- int i;
- DagAdjList *itA;
- int minheight;
-
- /* fprintf(stderr, "starting BFS\n ------------\n"); */
- nqueue = queue_create(DAGQUEUEALLOC);
- for (i = 0; i < 50; i++)
- pos[i] = 0;
-
- /* Init
- * dagnode.first is always the root (scene)
- */
- node = MainDag->DagNode.first;
- while (node) {
- node->color = DAG_WHITE;
- node->BFS_dist = 9999;
- node->k = 0;
- node = node->next;
- }
-
- node = MainDag->DagNode.first;
- if (node->color == DAG_WHITE) {
- node->color = DAG_GRAY;
- node->BFS_dist = 1;
- push_queue(nqueue, node);
- while (nqueue->count) {
- node = pop_queue(nqueue);
-
- minheight = pos[node->BFS_dist];
- itA = node->child;
- while (itA != NULL) {
- if (itA->node->color == DAG_WHITE) {
- itA->node->color = DAG_GRAY;
- itA->node->BFS_dist = node->BFS_dist + 1;
- itA->node->k = (float) minheight;
- push_queue(nqueue, itA->node);
- }
-
- else {
- fprintf(stderr, "bfs not dag tree edge color :%i\n", itA->node->color);
- }
-
-
- itA = itA->next;
- }
- if (pos[node->BFS_dist] > node->k) {
- pos[node->BFS_dist] += 1;
- node->k = (float) pos[node->BFS_dist];
- }
- else {
- pos[node->BFS_dist] = (int) node->k + 1;
- }
- set_node_xy(node, node->BFS_dist * DEPSX * 2, pos[node->BFS_dist] * DEPSY * 2);
- node->color = DAG_BLACK;
-
- // fprintf(stderr, "BFS node : %20s %i %5.0f %5.0f\n", ((ID *) node->ob)->name, node->BFS_dist, node->x, node->y);
- }
- }
- queue_delete(nqueue);
-}
-
-int pre_and_post_BFS(DagForest *dag, short mask, graph_action_func pre_func, graph_action_func post_func, void **data)
-{
- DagNode *node;
-
- node = dag->DagNode.first;
- return pre_and_post_source_BFS(dag, mask, node, pre_func, post_func, data);
-}
-
-
-int pre_and_post_source_BFS(DagForest *dag, short mask, DagNode *source, graph_action_func pre_func, graph_action_func post_func, void **data)
-{
- DagNode *node;
- DagNodeQueue *nqueue;
- DagAdjList *itA;
- int retval = 0;
- /* fprintf(stderr, "starting BFS\n ------------\n"); */
-
- /* Init
- * dagnode.first is always the root (scene)
- */
- node = dag->DagNode.first;
- nqueue = queue_create(DAGQUEUEALLOC);
- while (node) {
- node->color = DAG_WHITE;
- node->BFS_dist = 9999;
- node = node->next;
- }
-
- node = source;
- if (node->color == DAG_WHITE) {
- node->color = DAG_GRAY;
- node->BFS_dist = 1;
- pre_func(node->ob, data);
-
- while (nqueue->count) {
- node = pop_queue(nqueue);
-
- itA = node->child;
- while (itA != NULL) {
- if ((itA->node->color == DAG_WHITE) && (itA->type & mask)) {
- itA->node->color = DAG_GRAY;
- itA->node->BFS_dist = node->BFS_dist + 1;
- push_queue(nqueue, itA->node);
- pre_func(node->ob, data);
- }
-
- else { /* back or cross edge */
- retval = 1;
- }
- itA = itA->next;
- }
- post_func(node->ob, data);
- node->color = DAG_BLACK;
-
- // fprintf(stderr, "BFS node : %20s %i %5.0f %5.0f\n", ((ID *) node->ob)->name, node->BFS_dist, node->x, node->y);
- }
- }
- queue_delete(nqueue);
- return retval;
-}
-
-/* non recursive version of DFS, return queue -- outer loop present to catch odd cases (first level cycles)*/
-DagNodeQueue *graph_dfs(void)
-{
- DagNode *node;
- DagNodeQueue *nqueue;
- DagNodeQueue *retqueue;
- int pos[50];
- int i;
- DagAdjList *itA;
- int time;
- int skip = 0;
- int minheight;
- int maxpos = 0;
- /* int is_cycle = 0; */ /* UNUSED */
- /*
- *fprintf(stderr, "starting DFS\n ------------\n");
- */
- nqueue = queue_create(DAGQUEUEALLOC);
- retqueue = queue_create(MainDag->numNodes);
- for (i = 0; i < 50; i++)
- pos[i] = 0;
-
- /* Init
- * dagnode.first is always the root (scene)
- */
- node = MainDag->DagNode.first;
- while (node) {
- node->color = DAG_WHITE;
- node->DFS_dist = 9999;
- node->DFS_dvtm = node->DFS_fntm = 9999;
- node->k = 0;
- node = node->next;
- }
-
- time = 1;
-
- node = MainDag->DagNode.first;
-
- do {
- if (node->color == DAG_WHITE) {
- node->color = DAG_GRAY;
- node->DFS_dist = 1;
- node->DFS_dvtm = time;
- time++;
- push_stack(nqueue, node);
-
- while (nqueue->count) {
- //graph_print_queue(nqueue);
-
- skip = 0;
- node = get_top_node_queue(nqueue);
-
- minheight = pos[node->DFS_dist];
-
- itA = node->child;
- while (itA != NULL) {
- if (itA->node->color == DAG_WHITE) {
- itA->node->DFS_dvtm = time;
- itA->node->color = DAG_GRAY;
-
- time++;
- itA->node->DFS_dist = node->DFS_dist + 1;
- itA->node->k = (float) minheight;
- push_stack(nqueue, itA->node);
- skip = 1;
- break;
- }
- else {
- if (itA->node->color == DAG_GRAY) { /* back edge */
- fprintf(stderr, "dfs back edge :%15s %15s\n", ((ID *) node->ob)->name, ((ID *) itA->node->ob)->name);
- /* is_cycle = 1; */ /* UNUSED */
- }
- else if (itA->node->color == DAG_BLACK) {
- /* already processed node but we may want later to change distance either to shorter to longer.
- * DFS_dist is the first encounter
- */
-#if 0
- if (node->DFS_dist >= itA->node->DFS_dist)
- itA->node->DFS_dist = node->DFS_dist + 1;
-
- fprintf(stderr, "dfs forward or cross edge :%15s %i-%i %15s %i-%i\n",
- ((ID *) node->ob)->name,
- node->DFS_dvtm,
- node->DFS_fntm,
- ((ID *) itA->node->ob)->name,
- itA->node->DFS_dvtm,
- itA->node->DFS_fntm);
-#endif
- }
- else
- fprintf(stderr, "dfs unknown edge\n");
- }
- itA = itA->next;
- }
-
- if (!skip) {
- node = pop_queue(nqueue);
- node->color = DAG_BLACK;
-
- node->DFS_fntm = time;
- time++;
- if (node->DFS_dist > maxpos)
- maxpos = node->DFS_dist;
- if (pos[node->DFS_dist] > node->k) {
- pos[node->DFS_dist] += 1;
- node->k = (float) pos[node->DFS_dist];
- }
- else {
- pos[node->DFS_dist] = (int) node->k + 1;
- }
- set_node_xy(node, node->DFS_dist * DEPSX * 2, pos[node->DFS_dist] * DEPSY * 2);
-
- // fprintf(stderr, "DFS node : %20s %i %i %i %i\n", ((ID *) node->ob)->name, node->BFS_dist, node->DFS_dist, node->DFS_dvtm, node->DFS_fntm );
-
- push_stack(retqueue, node);
-
- }
- }
- }
- node = node->next;
- } while (node);
-// fprintf(stderr, "i size : %i\n", maxpos);
-
- queue_delete(nqueue);
- return(retqueue);
-}
-
-/* unused */
-int pre_and_post_DFS(DagForest *dag, short mask, graph_action_func pre_func, graph_action_func post_func, void **data)
-{
- DagNode *node;
-
- node = dag->DagNode.first;
- return pre_and_post_source_DFS(dag, mask, node, pre_func, post_func, data);
-}
-
-int pre_and_post_source_DFS(DagForest *dag, short mask, DagNode *source, graph_action_func pre_func, graph_action_func post_func, void **data)
-{
- DagNode *node;
- DagNodeQueue *nqueue;
- DagAdjList *itA;
- int time;
- int skip = 0;
- int retval = 0;
- /*
- * fprintf(stderr, "starting DFS\n ------------\n");
- */
- nqueue = queue_create(DAGQUEUEALLOC);
-
- /* Init
- * dagnode.first is always the root (scene)
- */
- node = dag->DagNode.first;
- while (node) {
- node->color = DAG_WHITE;
- node->DFS_dist = 9999;
- node->DFS_dvtm = node->DFS_fntm = 9999;
- node->k = 0;
- node = node->next;
- }
-
- time = 1;
-
- node = source;
- do {
- if (node->color == DAG_WHITE) {
- node->color = DAG_GRAY;
- node->DFS_dist = 1;
- node->DFS_dvtm = time;
- time++;
- push_stack(nqueue, node);
- pre_func(node->ob, data);
-
- while (nqueue->count) {
- skip = 0;
- node = get_top_node_queue(nqueue);
-
- itA = node->child;
- while (itA != NULL) {
- if ((itA->node->color == DAG_WHITE) && (itA->type & mask) ) {
- itA->node->DFS_dvtm = time;
- itA->node->color = DAG_GRAY;
-
- time++;
- itA->node->DFS_dist = node->DFS_dist + 1;
- push_stack(nqueue, itA->node);
- pre_func(node->ob, data);
-
- skip = 1;
- break;
- }
- else {
- if (itA->node->color == DAG_GRAY) { // back edge
- retval = 1;
- }
-// else if (itA->node->color == DAG_BLACK) { // cross or forward
-//
-// }
- }
- itA = itA->next;
- }
-
- if (!skip) {
- node = pop_queue(nqueue);
- node->color = DAG_BLACK;
-
- node->DFS_fntm = time;
- time++;
- post_func(node->ob, data);
- }
- }
- }
- node = node->next;
- } while (node);
- queue_delete(nqueue);
- return(retval);
-}
-
-
-/* used to get the obs owning a datablock */
-DagNodeQueue *get_obparents(struct DagForest *dag, void *ob)
-{
- DagNode *node, *node1;
- DagNodeQueue *nqueue;
- DagAdjList *itA;
-
- node = dag_find_node(dag, ob);
- if (node == NULL) {
- return NULL;
- }
- else if (node->ancestor_count == 1) { /* simple case */
- nqueue = queue_create(1);
- push_queue(nqueue, node);
- }
- else { /* need to go over the whole dag for adj list */
- nqueue = queue_create(node->ancestor_count);
-
- node1 = dag->DagNode.first;
- do {
- if (node1->DFS_fntm > node->DFS_fntm) { /* a parent is finished after child. must check adj list */
- itA = node->child;
- while (itA != NULL) {
- if ((itA->node == node) && (itA->type == DAG_RL_DATA)) {
- push_queue(nqueue, node);
- }
- itA = itA->next;
- }
- }
- node1 = node1->next;
- } while (node1);
- }
- return nqueue;
-}
-
-DagNodeQueue *get_first_ancestors(struct DagForest *dag, void *ob)
-{
- DagNode *node, *node1;
- DagNodeQueue *nqueue;
- DagAdjList *itA;
-
- node = dag_find_node(dag, ob);
-
- /* need to go over the whole dag for adj list */
- nqueue = queue_create(node->ancestor_count);
-
- node1 = dag->DagNode.first;
- do {
- if (node1->DFS_fntm > node->DFS_fntm) {
- itA = node->child;
- while (itA != NULL) {
- if (itA->node == node) {
- push_queue(nqueue, node);
- }
- itA = itA->next;
- }
- }
- node1 = node1->next;
- } while (node1);
-
- return nqueue;
-}
-
-/* standard DFS list */
-DagNodeQueue *get_all_childs(struct DagForest *dag, void *ob)
-{
- DagNode *node;
- DagNodeQueue *nqueue;
- DagNodeQueue *retqueue;
- DagAdjList *itA;
- int time;
- int skip = 0;
-
- nqueue = queue_create(DAGQUEUEALLOC);
- retqueue = queue_create(dag->numNodes); /* was MainDag... why? (ton) */
-
- node = dag->DagNode.first;
- while (node) {
- node->color = DAG_WHITE;
- node = node->next;
- }
-
- time = 1;
-
- node = dag_find_node(dag, ob); /* could be done in loop above (ton) */
- if (node) { /* can be null for newly added objects */
-
- node->color = DAG_GRAY;
- time++;
- push_stack(nqueue, node);
-
- while (nqueue->count) {
-
- skip = 0;
- node = get_top_node_queue(nqueue);
-
- itA = node->child;
- while (itA != NULL) {
- if (itA->node->color == DAG_WHITE) {
- itA->node->DFS_dvtm = time;
- itA->node->color = DAG_GRAY;
-
- time++;
- push_stack(nqueue, itA->node);
- skip = 1;
- break;
- }
- itA = itA->next;
- }
-
- if (!skip) {
- node = pop_queue(nqueue);
- node->color = DAG_BLACK;
-
- time++;
- push_stack(retqueue, node);
- }
- }
- }
- queue_delete(nqueue);
- return(retqueue);
-}
-
-/* unused */
-#if 0
-short are_obs_related(struct DagForest *dag, void *ob1, void *ob2)
-{
- DagNode *node;
- DagAdjList *itA;
-
- node = dag_find_node(dag, ob1);
-
- itA = node->child;
- while (itA != NULL) {
- if (itA->node->ob == ob2) {
- return itA->node->type;
- }
- itA = itA->next;
- }
- return DAG_NO_RELATION;
-}
-#endif
-
-int is_acyclic(DagForest *dag)
-{
- return dag->is_acyclic;
-}
-
-void set_node_xy(DagNode *node, float x, float y)
-{
- node->x = x;
- node->y = y;
-}
-
-
/* debug test functions */
void graph_print_queue(DagNodeQueue *nqueue)
@@ -1757,12 +1213,12 @@ void graph_print_queue_dist(DagNodeQueue *nqueue)
fprintf(stderr, "\n");
}
-void graph_print_adj_list(void)
+void graph_print_adj_list(DagForest *dag)
{
DagNode *node;
DagAdjList *itA;
- node = (getMainDag())->DagNode.first;
+ node = dag->DagNode.first;
while (node) {
fprintf(stderr, "node : %s col: %i", ((ID *) node->ob)->name, node->color);
itA = node->child;
@@ -1973,6 +1429,15 @@ void DAG_scene_relations_update(Main *bmain, Scene *sce)
dag_scene_build(bmain, sce);
}
+void DAG_scene_free(Scene *sce)
+{
+ if (sce->theDag) {
+ free_forest(sce->theDag);
+ MEM_freeN(sce->theDag);
+ sce->theDag = NULL;
+ }
+}
+
static void lib_id_recalc_tag(Main *bmain, ID *id)
{
id->flag |= LIB_ID_RECALC;
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 23f3a3ad3fd..bc396d218df 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -986,9 +986,9 @@ typedef struct DriverVarTypeInfo {
float (*get_value)(ChannelDriver *driver, DriverVar *dvar);
/* allocation of target slots */
- int num_targets; /* number of target slots required */
+ int num_targets; /* number of target slots required */
const char *target_names[MAX_DRIVER_TARGETS]; /* UI names that should be given to the slots */
- int target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */
+ short target_flags[MAX_DRIVER_TARGETS]; /* flags defining the requirements for each slot */
} DriverVarTypeInfo;
/* Macro to begin definitions */
@@ -1014,7 +1014,7 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
PointerRNA id_ptr, ptr;
PropertyRNA *prop;
ID *id;
- int index;
+ int index = -1;
float value = 0.0f;
/* sanity check */
@@ -1029,6 +1029,7 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
printf("Error: driver has an invalid target to use\n");
if (G.debug & G_DEBUG) printf("\tpath = %s\n", dtar->rna_path);
driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
return 0.0f;
}
@@ -1039,7 +1040,7 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
if (RNA_path_resolve_full(&id_ptr, dtar->rna_path, &ptr, &prop, &index)) {
if (RNA_property_array_check(prop)) {
/* array */
- if (index < RNA_property_array_length(&ptr, prop)) {
+ if ((index >= 0) && (index < RNA_property_array_length(&ptr, prop))) {
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
value = (float)RNA_property_boolean_get_index(&ptr, prop, index);
@@ -1054,6 +1055,17 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
break;
}
}
+ else {
+ /* out of bounds */
+ if (G.debug & G_DEBUG) {
+ printf("Driver Evaluation Error: array index is out of bounds for %s -> %s (%d)",
+ id->name, dtar->rna_path, index);
+ }
+
+ driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ return 0.0f;
+ }
}
else {
/* not an array */
@@ -1074,16 +1086,19 @@ static float dtar_get_prop_val(ChannelDriver *driver, DriverTarget *dtar)
break;
}
}
-
}
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);
driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
return 0.0f;
}
+ /* if we're still here, we should be ok... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
return value;
}
@@ -1122,25 +1137,39 @@ static float dvar_eval_singleProp(ChannelDriver *driver, DriverVar *dvar)
/* evaluate 'rotation difference' driver variable */
static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar)
{
+ DriverTarget *dtar1 = &dvar->targets[0];
+ DriverTarget *dtar2 = &dvar->targets[1];
bPoseChannel *pchan, *pchan2;
float q1[4], q2[4], quat[4], angle;
/* get pose channels, and check if we've got two */
- pchan = dtar_get_pchan_ptr(driver, &dvar->targets[0]);
- pchan2 = dtar_get_pchan_ptr(driver, &dvar->targets[1]);
+ pchan = dtar_get_pchan_ptr(driver, dtar1);
+ pchan2 = dtar_get_pchan_ptr(driver, dtar2);
if (ELEM(NULL, pchan, pchan2)) {
/* disable this driver, since it doesn't work correctly... */
driver->flag |= DRIVER_FLAG_INVALID;
/* check what the error was */
- if ((pchan == NULL) && (pchan2 == NULL))
+ if ((pchan == NULL) && (pchan2 == NULL)) {
printf("Driver Evaluation Error: Rotational difference failed - first 2 targets invalid\n");
- else if (pchan == NULL)
+
+ dtar1->flag |= DTAR_FLAG_INVALID;
+ dtar2->flag |= DTAR_FLAG_INVALID;
+ }
+ else if (pchan == NULL) {
printf("Driver Evaluation Error: Rotational difference failed - first target not valid PoseChannel\n");
- else if (pchan2 == NULL)
+
+ dtar1->flag |= DTAR_FLAG_INVALID;
+ dtar2->flag &= ~DTAR_FLAG_INVALID;
+ }
+ else if (pchan2 == NULL) {
printf("Driver Evaluation Error: Rotational difference failed - second target not valid PoseChannel\n");
+ dtar1->flag &= ~DTAR_FLAG_INVALID;
+ dtar2->flag |= DTAR_FLAG_INVALID;
+ }
+
/* stop here... */
return 0.0f;
}
@@ -1163,22 +1192,53 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
{
float loc1[3] = {0.0f, 0.0f, 0.0f};
float loc2[3] = {0.0f, 0.0f, 0.0f};
+ short valid_targets = 0;
- /* get two location values */
- /* NOTE: for now, these are all just worldspace */
+ /* Perform two passes
+ *
+ * FIRST PASS - to just check that everything works...
+ * NOTE: we use loops here to reduce code duplication, though in practice,
+ * there can only be 2 items or else we run into some problems later
+ */
DRIVER_TARGETS_USED_LOOPER(dvar)
{
- /* get pointer to loc values to store in */
Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
- bPoseChannel *pchan;
- float tmp_loc[3];
/* check if this target has valid data */
if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
/* invalid target, so will not have enough targets */
driver->flag |= DRIVER_FLAG_INVALID;
- return 0.0f;
+ dtar->flag |= DTAR_FLAG_INVALID;
+ }
+ else {
+ /* target seems to be OK now... */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ valid_targets++;
}
+ }
+ DRIVER_TARGETS_LOOPER_END
+
+ /* make sure we have enough valid targets to use - all or nothing for now... */
+ if (valid_targets < dvar->num_targets) {
+ if (G.debug & G_DEBUG) {
+ printf("LocDiff DVar: not enough valid targets (n = %d) (a = %p, b = %p)\n",
+ valid_targets, dvar->targets[0].id, dvar->targets[1].id);
+ }
+ return 0.0f;
+ }
+
+
+ /* SECOND PASS: get two location values */
+ /* NOTE: for now, these are all just worldspace */
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ /* get pointer to loc values to store in */
+ Object *ob = (Object *)dtar_id_ensure_proxy_from(dtar->id);
+ bPoseChannel *pchan;
+ float tmp_loc[3];
+
+ /* after the checks above, the targets should be valid here... */
+ BLI_assert((ob != NULL) && (GS(ob->id.name) != ID_OB));
/* try to get posechannel */
pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
@@ -1264,8 +1324,13 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
if ((ob == NULL) || (GS(ob->id.name) != ID_OB)) {
/* invalid target, so will not have enough targets */
driver->flag |= DRIVER_FLAG_INVALID;
+ dtar->flag |= DTAR_FLAG_INVALID;
return 0.0f;
}
+ else {
+ /* target should be valid now */
+ dtar->flag &= ~DTAR_FLAG_INVALID;
+ }
/* try to get posechannel */
pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
@@ -1458,12 +1523,12 @@ void driver_change_variable_type(DriverVar *dvar, int type)
*/
DRIVER_TARGETS_USED_LOOPER(dvar)
{
- int flags = dvti->target_flags[tarIndex];
+ short flags = dvti->target_flags[tarIndex];
/* store the flags */
dtar->flag = flags;
- /* object ID types only, or idtype not yet initialized*/
+ /* object ID types only, or idtype not yet initialized */
if ((flags & DTAR_FLAG_ID_OB_ONLY) || (dtar->idtype == 0))
dtar->idtype = ID_OB;
}
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 960432d6b3d..87802ab8ee6 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -923,6 +923,8 @@ void BKE_mask_free(Main *bmain, Mask *mask)
SpaceLink *sl;
Scene *scene;
+ BKE_sequencer_clear_mask_in_clipboard(mask);
+
for (scr = bmain->screen.first; scr; scr = scr->id.next) {
for (area = scr->areabase.first; area; area = area->next) {
for (sl = area->spacedata.first; sl; sl = sl->next) {
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index c9c86e6739f..f6f60d03cf7 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -887,12 +887,11 @@ static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, MLoop *alll
int old, MEdge **alledge, int *_totedge)
{
MPoly *mpoly;
- MLoop *mloop;
MFace *mface;
MEdge *medge;
EdgeHash *hash = BLI_edgehash_new();
struct edgesort *edsort, *ed;
- int a, b, totedge = 0, final = 0;
+ int a, totedge = 0, final = 0;
/* we put all edges in array, sort them, and detect doubles that way */
@@ -973,13 +972,16 @@ static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, MLoop *alll
mpoly = allpoly;
for (a = 0; a < totpoly; a++, mpoly++) {
- mloop = allloop + mpoly->loopstart;
- for (b = 0; b < mpoly->totloop; b++) {
- int v1, v2;
-
- v1 = mloop[b].v;
- v2 = ME_POLY_LOOP_NEXT(mloop, mpoly, b)->v;
- mloop[b].e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(hash, v1, v2));
+ MLoop *ml, *ml_next;
+ int i = mpoly->totloop;
+
+ ml_next = allloop + mpoly->loopstart; /* first loop */
+ ml = &ml_next[i - 1]; /* last loop */
+
+ while (i-- != 0) {
+ ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(hash, ml->v, ml_next->v));
+ ml = ml_next;
+ ml_next++;
}
}
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 128b9ae242e..74d3645ea66 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -908,6 +908,12 @@ int BKE_mesh_validate_dm(DerivedMesh *dm)
TRUE, FALSE);
}
+/**
+ * Calculate edges from polygons
+ *
+ * \param mesh The mesh to add edges into
+ * \param update When true create new edges co-exist
+ */
void BKE_mesh_calc_edges(Mesh *mesh, int update)
{
CustomData edata;
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 2aeda614f07..b0566a6495f 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -424,7 +424,9 @@ ModifierData *modifiers_getLastPreview(struct Scene *scene, ModifierData *md, in
return tmp_md;
}
-/* NOTE: these aren't used anymore */
+/* NOTE: This is to support old files from before Blender supported modifiers,
+ * in some cases versioning code updates these so for new files this will
+ * return an empty list. */
ModifierData *modifiers_getVirtualModifierList(Object *ob)
{
/* Kinda hacky, but should be fine since we are never
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index eceac61ddb6..5519edca7ff 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -75,12 +75,17 @@
#include "BKE_node.h"
#include "BKE_image.h" /* openanim */
#include "BKE_tracking.h"
+#include "BKE_sequencer.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_moviecache.h"
+#ifdef WITH_OPENEXR
+#include "intern/openexr/openexr_multi.h"
+#endif
+
/*********************** movieclip buffer loaders *************************/
static int sequence_guess_offset(const char *full_name, int head_len, unsigned short numlen)
@@ -221,6 +226,15 @@ static ImBuf *movieclip_load_sequence_file(MovieClip *clip, MovieClipUser *user,
/* read ibuf */
ibuf = IMB_loadiffname(name, loadflag, colorspace);
+#ifdef WITH_OPENEXR
+ if (ibuf) {
+ if (ibuf->ftype == OPENEXR && ibuf->userdata) {
+ IMB_exr_close(ibuf->userdata);
+ ibuf->userdata = NULL;
+ }
+ }
+#endif
+
return ibuf;
}
@@ -1281,6 +1295,8 @@ void BKE_movieclip_build_proxy_frame(MovieClip *clip, int clip_flag, struct Movi
void BKE_movieclip_free(MovieClip *clip)
{
+ BKE_sequencer_clear_movieclip_in_clipboard(clip);
+
free_buffers(clip);
BKE_tracking_free(&clip->tracking);
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 86fe47268d6..3dbaab008f8 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -991,6 +991,12 @@ void nodeFreeNode(bNodeTree *ntree, bNode *node)
if (treetype->free_node_cache)
treetype->free_node_cache(ntree, node);
+
+ /* texture node has bad habit of keeping exec data around */
+ if (ntree->type == NTREE_TEXTURE && ntree->execdata) {
+ ntreeTexEndExecTree(ntree->execdata, 1);
+ ntree->execdata = NULL;
+ }
}
/* since it is called while free database, node->id is undefined */
@@ -1040,6 +1046,7 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const short do_id_user)
break;
case NTREE_TEXTURE:
ntreeTexEndExecTree(ntree->execdata, 1);
+ ntree->execdata = NULL;
break;
}
}
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 483dd2570e2..477ae27394f 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -1057,10 +1057,10 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
node->prim_indices,
node->totprim);
break;
- case PBVH_BMESH:
+ case PBVH_BMESH:
node->draw_buffers =
- GPU_build_bmesh_buffers(bvh->flags &
- PBVH_DYNTOPO_SMOOTH_SHADING);
+ GPU_build_bmesh_buffers(bvh->flags &
+ PBVH_DYNTOPO_SMOOTH_SHADING);
break;
}
@@ -1089,12 +1089,12 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
node->face_vert_indices,
bvh->show_diffuse_color);
break;
- case PBVH_BMESH:
+ case PBVH_BMESH:
GPU_update_bmesh_buffers(node->draw_buffers,
- bvh->bm,
- node->bm_faces,
- node->bm_unique_verts,
- node->bm_other_verts);
+ bvh->bm,
+ node->bm_faces,
+ node->bm_unique_verts,
+ node->bm_other_verts);
break;
}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 666c85d2f6b..386a8b27870 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -412,7 +412,7 @@ static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
do {
v = l_iter->v;
if (pbvh_bmesh_node_vert_use_count(bvh, f_node, v) == 1) {
- if (BLI_ghash_lookup(f_node->bm_unique_verts, v)) {
+ if (BLI_ghash_haskey(f_node->bm_unique_verts, v)) {
/* Find a different node that uses 'v' */
PBVHNode *new_node;
@@ -805,7 +805,8 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e, BMVert *v1,
/* Ensure that v1 is in the new face's node */
if (!BLI_ghash_haskey(n->bm_unique_verts, v1) &&
- !BLI_ghash_haskey(n->bm_other_verts, v1)) {
+ !BLI_ghash_haskey(n->bm_other_verts, v1))
+ {
BLI_ghash_insert(n->bm_other_verts, v1, NULL);
}
}
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 27c5e03132e..c8947730ea8 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -3566,7 +3566,7 @@ void BKE_ptcache_update_info(PTCacheID *pid)
BLI_snprintf(cache->info, sizeof(cache->info), IFACE_("%s, cache is outdated!"), mem_info);
}
else if (cache->flag & PTCACHE_FRAMES_SKIPPED) {
- BLI_snprintf(cache->info, sizeof(cache->info), IFACE_("%s, not exact since frame %i."),
+ BLI_snprintf(cache->info, sizeof(cache->info), IFACE_("%s, not exact since frame %i"),
mem_info, cache->last_exact);
}
else {
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 4c6bae122cd..d144ac927a6 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -347,6 +347,7 @@ void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild)
float capsule_height;
float hull_margin = 0.0f;
bool can_embed = true;
+ bool has_volume;
/* sanity check */
if (rbo == NULL)
@@ -404,11 +405,13 @@ void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild)
case RB_SHAPE_CONVEXH:
/* try to emged collision margin */
- if (!(rbo->flag & RBO_FLAG_USE_MARGIN))
+ has_volume = (MIN3(size[0], size[1], size[2]) > 0.0f);
+
+ if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && has_volume)
hull_margin = 0.04f;
new_shape = rigidbody_get_shape_convexhull_from_mesh(ob, hull_margin, &can_embed);
if (!(rbo->flag & RBO_FLAG_USE_MARGIN))
- rbo->margin = (can_embed) ? 0.04f : 0.0f; /* RB_TODO ideally we shouldn't directly change the margin here */
+ rbo->margin = (can_embed && has_volume) ? 0.04f : 0.0f; /* RB_TODO ideally we shouldn't directly change the margin here */
break;
case RB_SHAPE_TRIMESH:
new_shape = rigidbody_get_shape_trimesh_from_mesh(ob);
@@ -1217,10 +1220,10 @@ void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw)
/* ------------------ */
-/* Run RigidBody simulation for the specified physics world */
-void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
+/* Rebuild rigid body world */
+/* NOTE: this needs to be called before frame update to work correctly */
+void BKE_rigidbody_rebuild_world(Scene *scene, float ctime)
{
- float timestep;
RigidBodyWorld *rbw = scene->rigidbody_world;
PointCache *cache;
PTCacheID pid;
@@ -1230,16 +1233,12 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL);
cache = rbw->pointcache;
- rbw->flag &= ~RBW_FLAG_FRAME_UPDATE;
-
/* flag cache as outdated if we don't have a world or number of objects in the simulation has changed */
if (rbw->physics_world == NULL || rbw->numbodies != BLI_countlist(&rbw->group->gobject)) {
cache->flag |= PTCACHE_OUTDATED;
}
- if (ctime <= startframe) {
- rbw->ltime = startframe;
- /* reset and rebuild simulation if necessary */
+ if (ctime <= startframe + 1 && rbw->ltime == startframe) {
if (cache->flag & PTCACHE_OUTDATED) {
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
rigidbody_update_simulation(scene, rbw, true);
@@ -1247,12 +1246,25 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
cache->last_exact = 0;
cache->flag &= ~PTCACHE_REDO_NEEDED;
}
- return;
}
- /* rebuild world if it's outdated on second frame */
- else if (ctime == startframe + 1 && rbw->ltime == startframe && cache->flag & PTCACHE_OUTDATED) {
- BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
- rigidbody_update_simulation(scene, rbw, true);
+}
+
+/* Run RigidBody simulation for the specified physics world */
+void BKE_rigidbody_do_simulation(Scene *scene, float ctime)
+{
+ float timestep;
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+ PointCache *cache;
+ PTCacheID pid;
+ int startframe, endframe;
+
+ BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw);
+ BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL);
+ cache = rbw->pointcache;
+
+ if (ctime <= startframe) {
+ rbw->ltime = startframe;
+ return;
}
/* make sure we don't go out of cache frame range */
else if (ctime > endframe) {
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index e1e4563e89f..19eea279f79 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -306,6 +306,9 @@ void BKE_scene_free(Scene *sce)
{
Base *base;
+ /* check all sequences */
+ BKE_sequencer_clear_scene_in_allseqs(G.main, sce);
+
base = sce->base.first;
while (base) {
base->object->id.us--;
@@ -385,10 +388,7 @@ void BKE_scene_free(Scene *sce)
sce->toolsettings = NULL;
}
- if (sce->theDag) {
- free_forest(sce->theDag);
- MEM_freeN(sce->theDag);
- }
+ DAG_scene_free(sce);
if (sce->nodetree) {
ntreeFreeTree(sce->nodetree);
@@ -722,9 +722,6 @@ void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce)
if (sce1->set == sce)
sce1->set = NULL;
- /* check all sequences */
- BKE_sequencer_clear_scene_in_allseqs(bmain, sce);
-
/* check render layer nodes in other scenes */
clear_scene_in_nodes(bmain, sce);
@@ -1110,13 +1107,22 @@ static void scene_depsgraph_hack(Scene *scene, Scene *scene_parent)
}
-static void scene_flag_rbw_recursive(Scene *scene)
+static void scene_rebuild_rbw_recursive(Scene *scene, float ctime)
{
if (scene->set)
- scene_flag_rbw_recursive(scene->set);
+ scene_rebuild_rbw_recursive(scene->set, ctime);
if (BKE_scene_check_rigidbody_active(scene))
- scene->rigidbody_world->flag |= RBW_FLAG_FRAME_UPDATE;
+ BKE_rigidbody_rebuild_world(scene, ctime);
+}
+
+static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
+{
+ if (scene->set)
+ scene_do_rb_simulation_recursive(scene->set, ctime);
+
+ if (BKE_scene_check_rigidbody_active(scene))
+ BKE_rigidbody_do_simulation(scene, ctime);
}
static void scene_update_tagged_recursive(Main *bmain, Scene *scene, Scene *scene_parent)
@@ -1130,22 +1136,6 @@ static void scene_update_tagged_recursive(Main *bmain, Scene *scene, Scene *scen
if (scene->set)
scene_update_tagged_recursive(bmain, scene->set, scene_parent);
- /* run rigidbody sim
- * - calculate/read values from cache into RBO's, to get flushed
- * later when objects are evaluated (if they're tagged for eval)
- */
- // XXX: this position may still change, objects not being updated correctly before simulation is run
- // NOTE: current position is so that rigidbody sim affects other objects
- if (BKE_scene_check_rigidbody_active(scene) && scene->rigidbody_world->flag & RBW_FLAG_FRAME_UPDATE) {
- /* we use frame time of parent (this is "scene" itself for top-level of sets recursion),
- * as that is the active scene controlling all timing in file at the moment
- */
- float ctime = BKE_scene_frame_get(scene_parent);
-
- /* however, "scene" contains the rigidbody world needed for eval... */
- BKE_rigidbody_do_simulation(scene, ctime);
- }
-
/* scene objects */
for (base = scene->base.first; base; base = base->next) {
Object *ob = base->object;
@@ -1224,6 +1214,12 @@ void BKE_scene_update_for_newframe(Main *bmain, Scene *sce, unsigned int lay)
{
float ctime = BKE_scene_frame_get(sce);
Scene *sce_iter;
+
+ /* rebuild rigid body worlds before doing the actual frame update
+ * this needs to be done on start frame but animation playback usually starts one frame later
+ * we need to do it here to avoid rebuilding the world on every simulation change, which can be very expensive
+ */
+ scene_rebuild_rbw_recursive(sce, ctime);
/* keep this first */
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
@@ -1263,8 +1259,9 @@ void BKE_scene_update_for_newframe(Main *bmain, Scene *sce, unsigned int lay)
tag_main_idcode(bmain, ID_MA, FALSE);
tag_main_idcode(bmain, ID_LA, FALSE);
- /* flag rigid body worlds for update */
- scene_flag_rbw_recursive(sce);
+ /* run rigidbody sim */
+ /* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */
+ scene_do_rb_simulation_recursive(sce, ctime);
/* BKE_object_handle_update() on all objects, groups and sets */
scene_update_tagged_recursive(bmain, sce, sce);
diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c
index 9ea405ef636..a64a4895e9b 100644
--- a/source/blender/blenkernel/intern/seqmodifier.c
+++ b/source/blender/blenkernel/intern/seqmodifier.c
@@ -237,9 +237,9 @@ static void curves_apply_threaded(int width, int height, unsigned char *rect, fl
rgb_uchar_to_float(t, mask_rect + pixel_index);
- tempc[0] = pixel[0] * (1.0f - t[0]) + result[0] * t[0];
- tempc[1] = pixel[1] * (1.0f - t[1]) + result[1] * t[1];
- tempc[2] = pixel[2] * (1.0f - t[2]) + result[2] * t[2];
+ tempc[0] = tempc[0] * (1.0f - t[0]) + result[0] * t[0];
+ tempc[1] = tempc[1] * (1.0f - t[1]) + result[1] * t[1];
+ tempc[2] = tempc[2] * (1.0f - t[2]) + result[2] * t[2];
}
else {
tempc[0] = result[0];
@@ -438,7 +438,7 @@ static void brightcontrast_apply_threaded(int width, int height, unsigned char *
unsigned char *m = mask_rect + pixel_index;
float t = (float) m[c] / 255.0f;
- v = (float) pixel[c] * (1.0f - t) + v * t;
+ v = (float) pixel[c] / 255.0f * (1.0f - t) + v * t;
}
pixel[c] = FTOCHAR(v);
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 68618287546..613c02c173b 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -815,6 +815,33 @@ void BKE_sequencer_clear_scene_in_allseqs(Main *bmain, Scene *scene)
BKE_sequencer_base_recursive_apply(&scene_iter->ed->seqbase, clear_scene_in_allseqs_cb, scene);
}
}
+
+ /* also clear clipboard */
+ BKE_sequencer_base_recursive_apply(&seqbase_clipboard, clear_scene_in_allseqs_cb, scene);
+}
+
+static int clear_movieclip_in_clipboard_cb(Sequence *seq, void *arg_pt)
+{
+ if (seq->clip == (MovieClip *)arg_pt)
+ seq->clip = NULL;
+ return 1;
+}
+
+void BKE_sequencer_clear_movieclip_in_clipboard(MovieClip *clip)
+{
+ BKE_sequencer_base_recursive_apply(&seqbase_clipboard, clear_movieclip_in_clipboard_cb, clip);
+}
+
+static int clear_mask_in_clipboard_cb(Sequence *seq, void *arg_pt)
+{
+ if (seq->mask == (Mask *)arg_pt)
+ seq->mask = NULL;
+ return 1;
+}
+
+void BKE_sequencer_clear_mask_in_clipboard(Mask *mask)
+{
+ BKE_sequencer_base_recursive_apply(&seqbase_clipboard, clear_mask_in_clipboard_cb, mask);
}
typedef struct SeqUniqueInfo {
@@ -1544,8 +1571,11 @@ static void color_balance_byte_byte(StripColorBalance *cb_, unsigned char *rect,
for (c = 0; c < 3; c++) {
float t = color_balance_fl(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul);
- if (m)
- p[c] = p[c] * (1.0f - (float)m[c] / 255.0f) + t * m[c];
+ if (m) {
+ float m_normal = (float) m[c] / 255.0f;
+
+ p[c] = p[c] * (1.0f - m_normal) + t * m_normal;
+ }
else
p[c] = t;
}
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 74c0a76f82d..184984352ba 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -2560,6 +2560,7 @@ int txt_replace_char(Text *text, unsigned int add)
memcpy(text->curl->line + text->curc, ch, add_size);
text->curc += add_size;
+ text->curl->len += add_size - del_size;
txt_pop_sel(text);
txt_make_dirty(text);
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 1a7458f531c..f63a1f2cec0 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -1429,6 +1429,27 @@ void BKE_tracking_camera_get_reconstructed_interpolate(MovieTracking *tracking,
/*********************** Distortion/Undistortion *************************/
+#ifdef WITH_LIBMV
+static void cameraIntrinscisOptionsFromTracking(libmv_cameraIntrinsicsOptions *camera_intrinsics_options,
+ MovieTracking *tracking, int calibration_width, int calibration_height)
+{
+ MovieTrackingCamera *camera = &tracking->camera;
+ float aspy = 1.0f / tracking->camera.pixel_aspect;
+
+ camera_intrinsics_options->focal_length = camera->focal;
+
+ camera_intrinsics_options->principal_point_x = camera->principal[0];
+ camera_intrinsics_options->principal_point_y = camera->principal[1] * aspy;
+
+ camera_intrinsics_options->k1 = camera->k1;
+ camera_intrinsics_options->k2 = camera->k2;
+ camera_intrinsics_options->k3 = camera->k3;
+
+ camera_intrinsics_options->image_width = calibration_width;
+ camera_intrinsics_options->image_height = (double) calibration_height * aspy;
+}
+#endif
+
MovieDistortion *BKE_tracking_distortion_new(void)
{
MovieDistortion *distortion;
@@ -1441,28 +1462,23 @@ MovieDistortion *BKE_tracking_distortion_new(void)
void BKE_tracking_distortion_update(MovieDistortion *distortion, MovieTracking *tracking,
int calibration_width, int calibration_height)
{
- MovieTrackingCamera *camera = &tracking->camera;
- float aspy = 1.0f / tracking->camera.pixel_aspect;
-
#ifdef WITH_LIBMV
+ libmv_cameraIntrinsicsOptions camera_intrinsics_options;
+
+ cameraIntrinscisOptionsFromTracking(&camera_intrinsics_options, tracking,
+ calibration_width, calibration_height);
+
if (!distortion->intrinsics) {
- distortion->intrinsics = libmv_CameraIntrinsicsNew(camera->focal,
- camera->principal[0], camera->principal[1] * aspy,
- camera->k1, camera->k2, camera->k3,
- calibration_width, calibration_height * aspy);
+ distortion->intrinsics = libmv_CameraIntrinsicsNew(&camera_intrinsics_options);
}
else {
- libmv_CameraIntrinsicsUpdate(distortion->intrinsics, camera->focal,
- camera->principal[0], camera->principal[1] * aspy,
- camera->k1, camera->k2, camera->k3,
- calibration_width, calibration_height * aspy);
+ libmv_CameraIntrinsicsUpdate(distortion->intrinsics, &camera_intrinsics_options);
}
#else
(void) distortion;
+ (void) tracking;
(void) calibration_width;
(void) calibration_height;
- (void) camera;
- (void) aspy;
#endif
}
@@ -1543,15 +1559,17 @@ void BKE_tracking_distort_v2(MovieTracking *tracking, const float co[2], float r
MovieTrackingCamera *camera = &tracking->camera;
#ifdef WITH_LIBMV
+ libmv_cameraIntrinsicsOptions camera_intrinsics_options;
double x, y;
float aspy = 1.0f / tracking->camera.pixel_aspect;
+ cameraIntrinscisOptionsFromTracking(&camera_intrinsics_options, tracking, 0, 0);
+
/* normalize coords */
x = (co[0] - camera->principal[0]) / camera->focal;
y = (co[1] - camera->principal[1] * aspy) / camera->focal;
- libmv_applyCameraIntrinsics(camera->focal, camera->principal[0], camera->principal[1] * aspy,
- camera->k1, camera->k2, camera->k3, x, y, &x, &y);
+ libmv_applyCameraIntrinsics(&camera_intrinsics_options, x, y, &x, &y);
/* result is in image coords already */
r_co[0] = x;
@@ -1568,11 +1586,13 @@ void BKE_tracking_undistort_v2(MovieTracking *tracking, const float co[2], float
MovieTrackingCamera *camera = &tracking->camera;
#ifdef WITH_LIBMV
+ libmv_cameraIntrinsicsOptions camera_intrinsics_options;
double x = co[0], y = co[1];
float aspy = 1.0f / tracking->camera.pixel_aspect;
- libmv_InvertIntrinsics(camera->focal, camera->principal[0], camera->principal[1] * aspy,
- camera->k1, camera->k2, camera->k3, x, y, &x, &y);
+ cameraIntrinscisOptionsFromTracking(&camera_intrinsics_options, tracking, 0, 0);
+
+ libmv_InvertIntrinsics(&camera_intrinsics_options, x, y, &x, &y);
r_co[0] = x * camera->focal + camera->principal[0];
r_co[1] = y * camera->focal + camera->principal[1] * aspy;
@@ -2642,6 +2662,8 @@ typedef struct MovieReconstructContext {
float principal_point[2];
float k1, k2, k3;
+ int width, height;
+
float reprojection_error;
TracksMap *tracks_map;
@@ -2702,11 +2724,13 @@ static void reconstruct_retrieve_libmv_intrinscis(MovieReconstructContext *conte
&k1, &k2, &k3, &width, &height);
tracking->camera.focal = focal_length;
- tracking->camera.principal[0] = principal_x;
+ tracking->camera.principal[0] = principal_x;
tracking->camera.principal[1] = principal_y / aspy;
+
tracking->camera.k1 = k1;
tracking->camera.k2 = k2;
+ tracking->camera.k3 = k3;
}
static int reconstruct_retrieve_libmv_tracks(MovieReconstructContext *context, MovieTracking *tracking)
@@ -2840,10 +2864,10 @@ static int reconstruct_refine_intrinsics_get_flags(MovieTracking *tracking, Movi
flags |= LIBMV_REFINE_PRINCIPAL_POINT;
if (refine & REFINE_RADIAL_DISTORTION_K1)
- flags |= REFINE_RADIAL_DISTORTION_K1;
+ flags |= LIBMV_REFINE_RADIAL_DISTORTION_K1;
if (refine & REFINE_RADIAL_DISTORTION_K2)
- flags |= REFINE_RADIAL_DISTORTION_K2;
+ flags |= LIBMV_REFINE_RADIAL_DISTORTION_K2;
return flags;
}
@@ -2914,6 +2938,9 @@ MovieReconstructContext *BKE_tracking_reconstruction_context_new(MovieTracking *
context->principal_point[0] = camera->principal[0];
context->principal_point[1] = camera->principal[1] * aspy;
+ context->width = width;
+ context->height = height;
+
context->k1 = camera->k1;
context->k2 = camera->k2;
context->k3 = camera->k3;
@@ -2996,6 +3023,34 @@ static void reconstruct_update_solve_cb(void *customdata, double progress, const
BLI_snprintf(progressdata->stats_message, progressdata->message_size, "Solving camera | %s", message);
}
+
+static void camraIntrincicsOptionsFromContext(libmv_cameraIntrinsicsOptions *camera_intrinsics_options,
+ MovieReconstructContext *context)
+{
+ camera_intrinsics_options->focal_length = context->focal_length;
+
+ camera_intrinsics_options->principal_point_x = context->principal_point[0];
+ camera_intrinsics_options->principal_point_y = context->principal_point[1];
+
+ camera_intrinsics_options->k1 = context->k1;
+ camera_intrinsics_options->k2 = context->k2;
+ camera_intrinsics_options->k3 = context->k3;
+
+ camera_intrinsics_options->image_width = context->width;
+ camera_intrinsics_options->image_height = context->height;
+}
+
+static void reconstructionOptionsFromContext(libmv_reconstructionOptions *reconstruction_options,
+ MovieReconstructContext *context)
+{
+ reconstruction_options->keyframe1 = context->keyframe1;
+ reconstruction_options->keyframe2 = context->keyframe2;
+
+ reconstruction_options->refine_intrinsics = context->refine_flags;
+
+ reconstruction_options->success_threshold = context->success_threshold;
+ reconstruction_options->use_fallback_reconstruction = context->use_fallback_reconstruction;
+}
#endif
void BKE_tracking_reconstruction_solve(MovieReconstructContext *context, short *stop, short *do_update,
@@ -3006,32 +3061,28 @@ void BKE_tracking_reconstruction_solve(MovieReconstructContext *context, short *
ReconstructProgressData progressdata;
+ libmv_cameraIntrinsicsOptions camera_intrinsics_options;
+ libmv_reconstructionOptions reconstruction_options;
+
progressdata.stop = stop;
progressdata.do_update = do_update;
progressdata.progress = progress;
progressdata.stats_message = stats_message;
progressdata.message_size = message_size;
+ camraIntrincicsOptionsFromContext(&camera_intrinsics_options, context);
+ reconstructionOptionsFromContext(&reconstruction_options, context);
+
if (context->motion_flag & TRACKING_MOTION_MODAL) {
context->reconstruction = libmv_solveModal(context->tracks,
- context->focal_length,
- context->principal_point[0], context->principal_point[1],
- context->k1, context->k2, context->k3,
+ &camera_intrinsics_options,
+ &reconstruction_options,
reconstruct_update_solve_cb, &progressdata);
}
else {
- struct libmv_reconstructionOptions options;
-
- options.success_threshold = context->success_threshold;
- options.use_fallback_reconstruction = context->use_fallback_reconstruction;
-
context->reconstruction = libmv_solveReconstruction(context->tracks,
- context->keyframe1, context->keyframe2,
- context->refine_flags,
- context->focal_length,
- context->principal_point[0], context->principal_point[1],
- context->k1, context->k2, context->k3,
- &options,
+ &camera_intrinsics_options,
+ &reconstruction_options,
reconstruct_update_solve_cb, &progressdata);
}
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index c4e17b1ed48..13f47d94160 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -260,6 +260,11 @@ MINLINE void madd_sh_shfl(float r[9], const float sh[3], const float f);
/********************************* Form Factor *******************************/
+float form_factor_quad(const float p[3], const float n[3],
+ const float q0[3], const float q1[3], const float q2[3], const float q3[3]);
+int form_factor_visible_quad(const float p[3], const float n[3],
+ const float v0[3], const float v1[3], const float v2[3],
+ float q0[3], float q1[3], float q2[3], float q3[3]);
float form_factor_hemi_poly(float p[3], float n[3],
float v1[3], float v2[3], float v3[3], float v4[3]);
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index 95ad786c7c2..bbafd28ddbc 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -399,7 +399,8 @@ typedef bool _BLI_Bool;
# define BLI_assert(a) (void)0
#endif
-#if (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 406)) /* gcc4.6+ only */
+/* C++ can't use _Static_assert, expects static_assert() but c++0x only */
+#if (!defined(__cplusplus)) && (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 406)) /* gcc4.6+ only */
# define BLI_STATIC_ASSERT(a, msg) _Static_assert(a, msg);
#else
/* TODO msvc, clang */
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index baca7bb8f8a..8f7ecdcfde8 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -3171,9 +3171,9 @@ static void vec_add_dir(float r[3], const float v1[3], const float v2[3], const
r[2] = v1[2] + fac * (v2[2] - v1[2]);
}
-static int ff_visible_quad(const float p[3], const float n[3],
- const float v0[3], const float v1[3], const float v2[3],
- float q0[3], float q1[3], float q2[3], float q3[3])
+int form_factor_visible_quad(const float p[3], const float n[3],
+ const float v0[3], const float v1[3], const float v2[3],
+ float q0[3], float q1[3], float q2[3], float q3[3])
{
static const float epsilon = 1e-6f;
float c, sd[3];
@@ -3532,8 +3532,8 @@ static void ff_normalize(float n[3])
}
}
-static float ff_quad_form_factor(const float p[3], const float n[3],
- const float q0[3], const float q1[3], const float q2[3], const float q3[3])
+float form_factor_quad(const float p[3], const float n[3],
+ const float q0[3], const float q1[3], const float q2[3], const float q3[3])
{
float r0[3], r1[3], r2[3], r3[3], g0[3], g1[3], g2[3], g3[3];
float a1, a2, a3, a4, dot1, dot2, dot3, dot4, result;
@@ -3579,11 +3579,11 @@ float form_factor_hemi_poly(float p[3], float n[3], float v1[3], float v2[3], fl
* covered by a quad or triangle, cosine weighted */
float q0[3], q1[3], q2[3], q3[3], contrib = 0.0f;
- if (ff_visible_quad(p, n, v1, v2, v3, q0, q1, q2, q3))
- contrib += ff_quad_form_factor(p, n, q0, q1, q2, q3);
+ if (form_factor_visible_quad(p, n, v1, v2, v3, q0, q1, q2, q3))
+ contrib += form_factor_quad(p, n, q0, q1, q2, q3);
- if (v4 && ff_visible_quad(p, n, v1, v3, v4, q0, q1, q2, q3))
- contrib += ff_quad_form_factor(p, n, q0, q1, q2, q3);
+ if (v4 && form_factor_visible_quad(p, n, v1, v3, v4, q0, q1, q2, q3))
+ contrib += form_factor_quad(p, n, q0, q1, q2, q3);
return contrib;
}
diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c
index 686484ef1db..a74f82ae965 100644
--- a/source/blender/blenlib/intern/threads.c
+++ b/source/blender/blenlib/intern/threads.c
@@ -429,12 +429,16 @@ void BLI_spin_unlock(SpinLock *spin)
#endif
}
+#ifndef __APPLE__
void BLI_spin_end(SpinLock *spin)
{
-#ifndef __APPLE__
pthread_spin_destroy(spin);
-#endif
}
+#else
+void BLI_spin_end(SpinLock *UNUSED(spin))
+{
+}
+#endif
/* Read/Write Mutex Lock */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 44a73fa14a0..b804a751b18 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -7564,6 +7564,23 @@ static void do_version_node_fix_translate_wrapping(void *UNUSED(data), ID *UNUSE
}
}
+static void do_version_node_straight_image_alpha_workaround(void *data, ID *UNUSED(id), bNodeTree *ntree)
+{
+ FileData *fd = (FileData *) data;
+ bNode *node;
+
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == CMP_NODE_IMAGE) {
+ Image *image = blo_do_versions_newlibadr(fd, ntree->id.lib, node->id);
+
+ if (image) {
+ if ((image->flag & IMA_DO_PREMUL) == 0 && image->alpha_mode == IMA_ALPHA_STRAIGHT)
+ node->custom1 |= CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT;
+ }
+ }
+ }
+}
+
static void do_version_node_fix_internal_links_264(void *UNUSED(data), ID *UNUSED(id), bNodeTree *ntree)
{
bNode *node;
@@ -7954,7 +7971,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
prop = BKE_bproperty_object_get(ob, "Text");
if (prop) {
BKE_reportf_wrap(fd->reports, RPT_WARNING,
- TIP_("Game property name conflict in object '%s':\ntext objects reserve the "
+ TIP_("Game property name conflict in object '%s': text objects reserve the "
"['Text'] game property to change their content through logic bricks"),
ob->id.name + 2);
}
@@ -8857,6 +8874,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
Scene *scene;
Image *image, *nimage;
Tex *tex, *otex;
+ bNodeTreeType *ntreetype;
+ bNodeTree *ntree;
for (scene = main->scene.first; scene; scene = scene->id.next) {
Sequence *seq;
@@ -8961,6 +8980,13 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
for (image = main->image.first; image; image = image->id.next)
image->flag &= ~IMA_DONE_TAG;
+
+ ntreetype = ntreeGetType(NTREE_COMPOSIT);
+ if (ntreetype && ntreetype->foreach_nodetree)
+ ntreetype->foreach_nodetree(main, fd, do_version_node_straight_image_alpha_workaround);
+
+ for (ntree = main->nodetree.first; ntree; ntree = ntree->id.next)
+ do_version_node_straight_image_alpha_workaround(fd, NULL, ntree);
}
if (main->versionfile < 265 || (main->versionfile == 265 && main->subversionfile < 7)) {
@@ -10450,7 +10476,8 @@ static ID *append_named_part(Main *mainl, FileData *fd, const char *idname, cons
}
else {
/* already linked */
- printf("append: already linked\n");
+ 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;
diff --git a/source/blender/bmesh/intern/bmesh_iterators_inline.h b/source/blender/bmesh/intern/bmesh_iterators_inline.h
index eef6544be89..faa109617d5 100644
--- a/source/blender/bmesh/intern/bmesh_iterators_inline.h
+++ b/source/blender/bmesh/intern/bmesh_iterators_inline.h
@@ -80,61 +80,61 @@ BLI_INLINE bool BM_iter_init(BMIter *iter, BMesh *bm, const char itype, void *da
BLI_assert(data != NULL);
iter->begin = bmiter__edge_of_vert_begin;
iter->step = bmiter__edge_of_vert_step;
- iter->vdata = data;
+ iter->vdata = (BMVert *)data;
break;
case BM_FACES_OF_VERT:
BLI_assert(data != NULL);
iter->begin = bmiter__face_of_vert_begin;
iter->step = bmiter__face_of_vert_step;
- iter->vdata = data;
+ iter->vdata = (BMVert *)data;
break;
case BM_LOOPS_OF_VERT:
BLI_assert(data != NULL);
iter->begin = bmiter__loop_of_vert_begin;
iter->step = bmiter__loop_of_vert_step;
- iter->vdata = data;
+ iter->vdata = (BMVert *)data;
break;
case BM_VERTS_OF_EDGE:
BLI_assert(data != NULL);
iter->begin = bmiter__vert_of_edge_begin;
iter->step = bmiter__vert_of_edge_step;
- iter->edata = data;
+ iter->edata = (BMEdge *)data;
break;
case BM_FACES_OF_EDGE:
BLI_assert(data != NULL);
iter->begin = bmiter__face_of_edge_begin;
iter->step = bmiter__face_of_edge_step;
- iter->edata = data;
+ iter->edata = (BMEdge *)data;
break;
case BM_VERTS_OF_FACE:
BLI_assert(data != NULL);
iter->begin = bmiter__vert_of_face_begin;
iter->step = bmiter__vert_of_face_step;
- iter->pdata = data;
+ iter->pdata = (BMFace *)data;
break;
case BM_EDGES_OF_FACE:
BLI_assert(data != NULL);
iter->begin = bmiter__edge_of_face_begin;
iter->step = bmiter__edge_of_face_step;
- iter->pdata = data;
+ iter->pdata = (BMFace *)data;
break;
case BM_LOOPS_OF_FACE:
BLI_assert(data != NULL);
iter->begin = bmiter__loop_of_face_begin;
iter->step = bmiter__loop_of_face_step;
- iter->pdata = data;
+ iter->pdata = (BMFace *)data;
break;
case BM_LOOPS_OF_LOOP:
BLI_assert(data != NULL);
iter->begin = bmiter__loops_of_loop_begin;
iter->step = bmiter__loops_of_loop_step;
- iter->ldata = data;
+ iter->ldata = (BMLoop *)data;
break;
case BM_LOOPS_OF_EDGE:
BLI_assert(data != NULL);
iter->begin = bmiter__loops_of_edge_begin;
iter->step = bmiter__loops_of_edge_step;
- iter->edata = data;
+ iter->edata = (BMEdge *)data;
break;
default:
/* should never happen */
diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c
index 5d8689b9da6..5e2404c9919 100644
--- a/source/blender/bmesh/operators/bmo_hull.c
+++ b/source/blender/bmesh/operators/bmo_hull.c
@@ -154,8 +154,9 @@ static void hull_output_triangles(BMesh *bm, GHash *hull_triangles)
const int next = (i == 2 ? 0 : i + 1);
BMEdge *e = BM_edge_exists(t->v[i], t->v[next]);
if (e &&
- BMO_elem_flag_test(bm, e, HULL_FLAG_INPUT) &&
- !BMO_elem_flag_test(bm, e, HULL_FLAG_HOLE)) {
+ BMO_elem_flag_test(bm, e, HULL_FLAG_INPUT) &&
+ !BMO_elem_flag_test(bm, e, HULL_FLAG_HOLE))
+ {
BMO_elem_flag_enable(bm, e, HULL_FLAG_OUTPUT_GEOM);
}
}
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index c270a1e6b20..221a5008f10 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -49,8 +49,8 @@ static const char *bc_get_joint_name(T *node)
return id.size() ? id.c_str() : node->getOriginalId().c_str();
}
-ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, AnimationImporterBase *anim, Scene *sce) :
- TransformReader(conv), scene(sce), empty(NULL), mesh_importer(mesh), anim_importer(anim) {
+ArmatureImporter::ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce) :
+ TransformReader(conv), scene(sce), empty(NULL), mesh_importer(mesh) {
}
ArmatureImporter::~ArmatureImporter()
diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h
index b07edfbf34d..2a8f1a65e21 100644
--- a/source/blender/collada/ArmatureImporter.h
+++ b/source/blender/collada/ArmatureImporter.h
@@ -96,7 +96,6 @@ private:
std::map<COLLADAFW::UniqueId, Object*> unskinned_armature_map;
MeshImporterBase *mesh_importer;
- AnimationImporterBase *anim_importer;
// This is used to store data passed in write_controller_data.
// Arrays from COLLADAFW::SkinControllerData lose ownership, so do this class members
@@ -138,7 +137,7 @@ private:
TagsMap uid_tags_map;
public:
- ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, AnimationImporterBase *anim, Scene *sce);
+ ArmatureImporter(UnitConverter *conv, MeshImporterBase *mesh, Scene *sce);
~ArmatureImporter();
void add_joint(COLLADAFW::Node *node, bool root, Object *parent, Scene *sce);
diff --git a/source/blender/collada/CMakeLists.txt b/source/blender/collada/CMakeLists.txt
index 326ca2b9937..8747d2995f2 100644
--- a/source/blender/collada/CMakeLists.txt
+++ b/source/blender/collada/CMakeLists.txt
@@ -38,7 +38,7 @@ set(INC
../../../intern/guardedalloc
../ikplugin
../../../intern/iksolver/extern
-
+ ../bmesh
)
set(INC_SYS
diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp
index 41693d4d680..6b367b9cea9 100644
--- a/source/blender/collada/ControllerExporter.cpp
+++ b/source/blender/collada/ControllerExporter.cpp
@@ -201,13 +201,12 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
bool use_instantiation = this->export_settings->use_object_instantiation;
Mesh *me;
- if (this->export_settings->apply_modifiers)
- me = bc_to_mesh_apply_modifiers(scene, ob, this->export_settings->export_mesh_type);
- else
- me = (Mesh *)ob->data;
+ me = bc_get_mesh_copy(scene,
+ ob,
+ this->export_settings->export_mesh_type,
+ this->export_settings->apply_modifiers,
+ this->export_settings->triangulate);
- BKE_mesh_tessface_ensure(me);
-
if (!me->dvert) return;
std::string controller_name = id_name(ob_arm);
@@ -239,6 +238,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
joint_index_by_def_index.push_back(-1);
}
+ int oob_counter = 0;
for (i = 0; i < me->totvert; i++) {
MDeformVert *vert = &me->dvert[i];
std::map<int, float> jw;
@@ -248,11 +248,18 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
for (j = 0; j < vert->totweight; j++) {
int idx = vert->dw[j].def_nr;
- if (idx >= 0) {
- int joint_index = joint_index_by_def_index[idx];
- if (joint_index != -1 && vert->dw[j].weight > 0.0f) {
- jw[joint_index] += vert->dw[j].weight;
- sumw += vert->dw[j].weight;
+ if (idx >= joint_index_by_def_index.size()) {
+ // XXX: Maybe better find out where and
+ // why the Out Of Bound indexes get created ?
+ oob_counter += 1;
+ }
+ else {
+ if (idx >= 0) {
+ int joint_index = joint_index_by_def_index[idx];
+ if (joint_index != -1 && vert->dw[j].weight > 0.0f) {
+ jw[joint_index] += vert->dw[j].weight;
+ sumw += vert->dw[j].weight;
+ }
}
}
}
@@ -274,16 +281,18 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
#endif
}
}
+
+ if (oob_counter > 0) {
+ fprintf(stderr, "Ignored %d Vertex weigths which use index to non existing VGroup %ld.\n", oob_counter, joint_index_by_def_index.size());
+ }
}
std::string weights_source_id = add_weights_source(me, controller_id, weights);
add_joints_element(&ob->defbase, joints_source_id, inv_bind_mat_source_id);
add_vertex_weights_element(weights_source_id, joints_source_id, vcounts, joints);
- if (this->export_settings->apply_modifiers)
- {
- BKE_libblock_free_us(&(G.main->mesh), me);
- }
+ BKE_libblock_free_us(&(G.main->mesh), me);
+
closeSkin();
closeController();
}
@@ -293,13 +302,11 @@ void ControllerExporter::export_morph_controller(Object *ob, Key *key)
bool use_instantiation = this->export_settings->use_object_instantiation;
Mesh *me;
- if (this->export_settings->apply_modifiers) {
- me = bc_to_mesh_apply_modifiers(scene, ob, this->export_settings->export_mesh_type);
- }
- else {
- me = (Mesh *)ob->data;
- }
- BKE_mesh_tessface_ensure(me);
+ me = bc_get_mesh_copy(scene,
+ ob,
+ this->export_settings->export_mesh_type,
+ this->export_settings->apply_modifiers,
+ this->export_settings->triangulate);
std::string controller_name = id_name(ob) + "-morph";
std::string controller_id = get_controller_id(key, ob);
@@ -320,10 +327,8 @@ void ControllerExporter::export_morph_controller(Object *ob, Key *key)
COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, morph_weights_id)));
targets.add();
- if (this->export_settings->apply_modifiers)
- {
- BKE_libblock_free_us(&(G.main->mesh), me);
- }
+ BKE_libblock_free_us(&(G.main->mesh), me);
+
//support for animations
//can also try the base element and param alternative
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index 2b906fa9ac2..49db6f033d9 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -104,7 +104,7 @@ DocumentImporter::DocumentImporter(bContext *C, const ImportSettings *import_set
import_settings(import_settings),
mImportStage(General),
mContext(C),
- armature_importer(&unit_converter, &mesh_importer, &anim_importer, CTX_data_scene(C)),
+ armature_importer(&unit_converter, &mesh_importer, CTX_data_scene(C)),
mesh_importer(&unit_converter, &armature_importer, CTX_data_scene(C)),
anim_importer(&unit_converter, &armature_importer, CTX_data_scene(C))
{
@@ -157,7 +157,8 @@ bool DocumentImporter::import()
delete ehandler;
- mesh_importer.bmeshConversion();
+ //XXX No longer needed (geometries are now created as bmesh)
+ //mesh_importer.bmeshConversion();
return true;
}
diff --git a/source/blender/collada/ExportSettings.h b/source/blender/collada/ExportSettings.h
index cf45b9b8391..ec71fb2747c 100644
--- a/source/blender/collada/ExportSettings.h
+++ b/source/blender/collada/ExportSettings.h
@@ -45,6 +45,7 @@ public:
bool include_material_textures;
bool use_texture_copies;
+ bool triangulate;
bool use_object_instantiation;
bool sort_by_name;
bool second_life;
diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp
index 4a6c5b43ce2..751628acf53 100644
--- a/source/blender/collada/GeometryExporter.cpp
+++ b/source/blender/collada/GeometryExporter.cpp
@@ -57,7 +57,6 @@ GeometryExporter::GeometryExporter(COLLADASW::StreamWriter *sw, const ExportSett
{
}
-
void GeometryExporter::exportGeom(Scene *sce)
{
openLibrary();
@@ -77,18 +76,16 @@ void GeometryExporter::operator()(Object *ob)
#endif
bool use_instantiation = this->export_settings->use_object_instantiation;
- Mesh *me;
- if (this->export_settings->apply_modifiers) {
- me = bc_to_mesh_apply_modifiers(mScene, ob, this->export_settings->export_mesh_type);
- }
- else {
- me = (Mesh *)ob->data;
- }
- BKE_mesh_tessface_ensure(me);
+ bool triangulate = this->export_settings->triangulate;
+ Mesh *me = bc_get_mesh_copy( mScene,
+ ob,
+ this->export_settings->export_mesh_type,
+ this->export_settings->apply_modifiers,
+ this->export_settings->triangulate);
std::string geom_id = get_geometry_id(ob, use_instantiation);
std::vector<Normal> nor;
- std::vector<Face> norind;
+ std::vector<BCPolygonNormalsIndices> norind;
// Skip if linked geometry was already exported from another reference
if (use_instantiation &&
@@ -117,12 +114,13 @@ void GeometryExporter::operator()(Object *ob)
bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
// writes <source> for uv coords if mesh has uv coords
- if (has_uvs)
+ if (has_uvs) {
createTexcoordsSource(geom_id, me);
+ }
- if (has_color)
+ if (has_color) {
createVertexColorSource(geom_id, me);
-
+ }
// <vertices>
COLLADASW::Vertices verts(mSW);
@@ -132,7 +130,7 @@ void GeometryExporter::operator()(Object *ob)
input_list.push_back(input);
verts.add();
- createLooseEdgeList(ob, me, geom_id, norind);
+ createLooseEdgeList(ob, me, geom_id);
// Only create Polylists if number of faces > 0
if (me->totface > 0) {
@@ -155,10 +153,6 @@ void GeometryExporter::operator()(Object *ob)
closeGeometry();
- if (this->export_settings->apply_modifiers) {
- BKE_libblock_free_us(&(G.main->mesh), me);
- }
-
if (this->export_settings->include_shapekeys) {
Key * key = BKE_key_from_object(ob);
if (key) {
@@ -171,16 +165,16 @@ void GeometryExporter::operator()(Object *ob)
}
}
}
-#if 0
- dm->release(dm);
-#endif
+
+ BKE_libblock_free_us(&(G.main->mesh), me);
+
}
void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
{
std::string geom_id = get_geometry_id(ob, false) + "_morph_" + translate_id(kb->name);
std::vector<Normal> nor;
- std::vector<Face> norind;
+ std::vector<BCPolygonNormalsIndices> norind;
if (exportedGeometry.find(geom_id) != exportedGeometry.end())
{
@@ -207,11 +201,13 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
bool has_uvs = (bool)CustomData_has_layer(&me->fdata, CD_MTFACE);
// writes <source> for uv coords if mesh has uv coords
- if (has_uvs)
+ if (has_uvs) {
createTexcoordsSource(geom_id, me);
+ }
- if (has_color)
+ if (has_color) {
createVertexColorSource(geom_id, me);
+ }
// <vertices>
@@ -245,8 +241,7 @@ void GeometryExporter::export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb)
void GeometryExporter::createLooseEdgeList(Object *ob,
Mesh *me,
- std::string& geom_id,
- std::vector<Face>& norind)
+ std::string& geom_id)
{
MEdge *medges = me->medge;
@@ -302,10 +297,12 @@ void GeometryExporter::createPolylist(short material_index,
Object *ob,
Mesh *me,
std::string& geom_id,
- std::vector<Face>& norind)
+ std::vector<BCPolygonNormalsIndices>& norind)
{
- MFace *mfaces = me->mface;
- int totfaces = me->totface;
+
+ MPoly *mpolys = me->mpoly;
+ MLoop *mloops = me->mloop;
+ int totpolys = me->totpoly;
// <vcount>
int i;
@@ -313,17 +310,12 @@ void GeometryExporter::createPolylist(short material_index,
std::vector<unsigned long> vcount_list;
// count faces with this material
- for (i = 0; i < totfaces; i++) {
- MFace *f = &mfaces[i];
+ for (i = 0; i < totpolys; i++) {
+ MPoly *p = &mpolys[i];
- if (f->mat_nr == material_index) {
+ if (p->mat_nr == material_index) {
faces_in_polylist++;
- if (f->v4 == 0) {
- vcount_list.push_back(3);
- }
- else {
- vcount_list.push_back(4);
- }
+ vcount_list.push_back(p->totloop);
}
}
@@ -385,21 +377,21 @@ void GeometryExporter::createPolylist(short material_index,
// performs the actual writing
polylist.prepareToAppendValues();
-
-
// <p>
int texindex = 0;
- for (i = 0; i < totfaces; i++) {
- MFace *f = &mfaces[i];
-
- if (f->mat_nr == material_index) {
-
- unsigned int *v = &f->v1;
- unsigned int *n = &norind[i].v1;
- for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
- polylist.appendValues(v[j]);
- polylist.appendValues(n[j]);
-
+ unsigned int vi = 0;
+ unsigned int ni = 0;
+ for (i = 0; i < totpolys; i++) {
+ MPoly *p = &mpolys[i];
+ int loop_count = p->totloop;
+
+ if (p->mat_nr == material_index) {
+ MLoop *l = &mloops[p->loopstart];
+ BCPolygonNormalsIndices normal_indices = norind[i];
+
+ for (int j = 0; j < loop_count; j++) {
+ polylist.appendValues(l[j].v);
+ polylist.appendValues(normal_indices[j]);
if (has_uvs)
polylist.appendValues(texindex + j);
@@ -408,14 +400,13 @@ void GeometryExporter::createPolylist(short material_index,
}
}
- texindex += 3;
- if (f->v4 != 0)
- texindex++;
+ texindex += loop_count;
}
polylist.finish();
}
+
// creates <source> for positions
void GeometryExporter::createVertsSource(std::string geom_id, Mesh *me)
{
@@ -485,6 +476,7 @@ void GeometryExporter::createVertexColorSource(std::string geom_id, Mesh *me)
source.finish();
}
+
std::string GeometryExporter::makeTexcoordSourceId(std::string& geom_id, int layer_index)
{
char suffix[20];
@@ -495,38 +487,21 @@ std::string GeometryExporter::makeTexcoordSourceId(std::string& geom_id, int lay
//creates <source> for texcoords
void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
{
-#if 0
- int totfaces = dm->getNumTessFaces(dm);
- MFace *mfaces = dm->getTessFaceArray(dm);
-#endif
- int totfaces = me->totface;
- MFace *mfaces = me->mface;
- int totuv = 0;
- int i;
+ int totpoly = me->totpoly;
+ int totuv = me->totloop;
+ MPoly *mpolys = me->mpoly;
- // count totuv
- for (i = 0; i < totfaces; i++) {
- MFace *f = &mfaces[i];
- if (f->v4 == 0) {
- totuv += 3;
- }
- else {
- totuv += 4;
- }
- }
-
- int num_layers = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+ int num_layers = CustomData_number_of_layers(&me->ldata, CD_MLOOPUV);
// write <source> for each layer
// each <source> will get id like meshName + "map-channel-1"
int map_index = 0;
- int active_uv_index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE)-1;
+ int active_uv_index = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
for (int a = 0; a < num_layers; a++) {
if (!this->export_settings->active_uv_only || a == active_uv_index) {
- MTFace *tface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, a);
- // char *name = CustomData_get_layer_name(&me->fdata, CD_MTFACE, a);
+ MLoopUV *mloops = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, a);
COLLADASW::FloatSourceF source(mSW);
std::string layer_id = makeTexcoordSourceId(geom_id, map_index++);
@@ -541,12 +516,12 @@ void GeometryExporter::createTexcoordsSource(std::string geom_id, Mesh *me)
source.prepareToAppendValues();
- for (i = 0; i < totfaces; i++) {
- MFace *f = &mfaces[i];
-
- for (int j = 0; j < (f->v4 == 0 ? 3 : 4); j++) {
- source.appendValues(tface[i].uv[j][0],
- tface[i].uv[j][1]);
+ for (int index = 0; index < totpoly; index++) {
+ MPoly *mpoly = mpolys+index;
+ MLoopUV *mloop = mloops+mpoly->loopstart;
+ for (int j = 0; j < mpoly->totloop; j++) {
+ source.appendValues(mloop[j].uv[0],
+ mloop[j].uv[1]);
}
}
@@ -586,53 +561,55 @@ void GeometryExporter::createNormalsSource(std::string geom_id, Mesh *me, std::v
source.finish();
}
-void GeometryExporter::create_normals(std::vector<Normal> &nor, std::vector<Face> &ind, Mesh *me)
+void GeometryExporter::create_normals(std::vector<Normal> &normals, std::vector<BCPolygonNormalsIndices> &polygons_normals, Mesh *me)
{
- int i, j, v;
MVert *vert = me->mvert;
- std::map<unsigned int, unsigned int> nshar;
-
- for (i = 0; i < me->totface; i++) {
- MFace *fa = &me->mface[i];
- Face f;
- unsigned int *nn = &f.v1;
- unsigned int *vv = &fa->v1;
-
- memset(&f, 0, sizeof(f));
- v = fa->v4 == 0 ? 3 : 4;
-
- if (!(fa->flag & ME_SMOOTH)) {
- Normal n;
- if (v == 4)
- normal_quad_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co, vert[fa->v4].co);
- else
- normal_tri_v3(&n.x, vert[fa->v1].co, vert[fa->v2].co, vert[fa->v3].co);
- nor.push_back(n);
+ std::map<unsigned int, unsigned int> shared_normal_indices;
+
+ for (int poly_index = 0; poly_index < me->totpoly; poly_index++) {
+ MPoly *mpoly = &me->mpoly[poly_index];
+ MLoop *mloops = me->mloop;
+
+ unsigned int last_normal_index = -1;
+ if (!(mpoly->flag & ME_SMOOTH)) {
+ // For flat faces calculate use face normal as vertex normal:
+
+ float vector[3];
+ BKE_mesh_calc_poly_normal(mpoly, mloops, vert, vector);
+
+ Normal n = { vector[0], vector[1], vector[2] };
+ normals.push_back(n);
+ last_normal_index++;
}
- for (j = 0; j < v; j++) {
- if (fa->flag & ME_SMOOTH) {
- if (nshar.find(*vv) != nshar.end())
- *nn = nshar[*vv];
+
+ MLoop *mloop = mloops + mpoly->loopstart;
+ BCPolygonNormalsIndices poly_indices;
+ for (int loop_index = 0; loop_index < mpoly->totloop; loop_index++) {
+ unsigned int vertex_index = mloop[loop_index].v;
+ if (mpoly->flag & ME_SMOOTH) {
+ if (shared_normal_indices.find(vertex_index) != shared_normal_indices.end())
+ poly_indices.add_index (shared_normal_indices[vertex_index]);
else {
- Normal n = {
- (float)vert[*vv].no[0] / 32767.0f,
- (float)vert[*vv].no[1] / 32767.0f,
- (float)vert[*vv].no[2] / 32767.0f
- };
- nor.push_back(n);
- *nn = (unsigned int)nor.size() - 1;
- nshar[*vv] = *nn;
+
+ float vector[3];
+ normal_short_to_float_v3(vector, vert[vertex_index].no);
+ normalize_v3(vector);
+
+ Normal n = { vector[0], vector[1], vector[2] };
+ normals.push_back(n);
+ last_normal_index++;
+
+ poly_indices.add_index(last_normal_index);
+ shared_normal_indices[vertex_index] = last_normal_index;
}
- vv++;
}
else {
- *nn = (unsigned int)nor.size() - 1;
+ poly_indices.add_index(last_normal_index);
}
- nn++;
}
- ind.push_back(f);
+ polygons_normals.push_back(poly_indices);
}
}
@@ -655,19 +632,4 @@ COLLADASW::URI GeometryExporter::makeUrl(std::string id)
return COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, id);
}
-#if 0
-int GeometryExporter::getTriCount(MFace *faces, int totface)
-{
- int i;
- int tris = 0;
- for (i = 0; i < totface; i++) {
- // if quad
- if (faces[i].v4 != 0)
- tris += 2;
- else
- tris++;
- }
- return tris;
-}
-#endif
diff --git a/source/blender/collada/GeometryExporter.h b/source/blender/collada/GeometryExporter.h
index 7cbbf0da8fa..4b1427c11ca 100644
--- a/source/blender/collada/GeometryExporter.h
+++ b/source/blender/collada/GeometryExporter.h
@@ -42,6 +42,7 @@
#include "DNA_key_types.h"
#include "ExportSettings.h"
+#include "collada_utils.h"
#include "BKE_key.h"
@@ -71,8 +72,7 @@ public:
void createLooseEdgeList(Object *ob,
Mesh *me,
- std::string& geom_id,
- std::vector<Face>& norind);
+ std::string& geom_id);
// powerful because it handles both cases when there is material and when there's not
void createPolylist(short material_index,
@@ -81,7 +81,7 @@ public:
Object *ob,
Mesh *me,
std::string& geom_id,
- std::vector<Face>& norind);
+ std::vector<BCPolygonNormalsIndices>& norind);
// creates <source> for positions
void createVertsSource(std::string geom_id, Mesh *me);
@@ -92,11 +92,12 @@ public:
//creates <source> for texcoords
void createTexcoordsSource(std::string geom_id, Mesh *me);
+ void createTesselatedTexcoordsSource(std::string geom_id, Mesh *me);
//creates <source> for normals
void createNormalsSource(std::string geom_id, Mesh *me, std::vector<Normal>& nor);
- void create_normals(std::vector<Normal> &nor, std::vector<Face> &ind, Mesh *me);
+ void create_normals(std::vector<Normal> &nor, std::vector<BCPolygonNormalsIndices> &ind, Mesh *me);
std::string getIdBySemantics(std::string geom_id, COLLADASW::InputSemantic::Semantics type, std::string other_suffix = "");
@@ -106,7 +107,6 @@ public:
void export_key_mesh(Object *ob, Mesh *me, KeyBlock *kb);
- /* int getTriCount(MFace *faces, int totface);*/
private:
std::set<std::string> exportedGeometry;
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index 26915f37002..69944563b6a 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -173,83 +173,30 @@ void UVDataWrapper::getUV(int uv_index, float *uv)
}
}
-void MeshImporter::set_face_indices(MFace *mface, unsigned int *indices, bool quad)
-{
- mface->v1 = indices[0];
- mface->v2 = indices[1];
- mface->v3 = indices[2];
- if (quad) mface->v4 = indices[3];
- else mface->v4 = 0;
-#ifdef COLLADA_DEBUG
- // fprintf(stderr, "%u, %u, %u\n", indices[0], indices[1], indices[2]);
-#endif
-}
-
-// not used anymore, test_index_face from blenkernel is better
-#if 0
-// change face indices order so that v4 is not 0
-void MeshImporter::rotate_face_indices(MFace *mface)
-{
- mface->v4 = mface->v1;
- mface->v1 = mface->v2;
- mface->v2 = mface->v3;
- mface->v3 = 0;
+MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce) : unitconverter(unitconv), scene(sce), armature_importer(arm) {
}
-#endif
-void MeshImporter::set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
- COLLADAFW::IndexList& index_list, unsigned int *tris_indices)
+void MeshImporter::set_poly_indices(MPoly *mpoly, MLoop *mloop, int loop_index, unsigned int *indices, int loop_count)
{
- // per face vertex indices, this means for quad we have 4 indices, not 8
- COLLADAFW::UIntValuesArray& indices = index_list.getIndices();
+ mpoly->loopstart = loop_index;
+ mpoly->totloop = loop_count;
- uvs.getUV(indices[tris_indices[0]], mtface->uv[0]);
- uvs.getUV(indices[tris_indices[1]], mtface->uv[1]);
- uvs.getUV(indices[tris_indices[2]], mtface->uv[2]);
+ for (int index=0; index < loop_count; index++) {
+ mloop->v = indices[index];
+ mloop++;
+ }
}
-void MeshImporter::set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
- COLLADAFW::IndexList& index_list, int index, bool quad)
+void MeshImporter::set_face_uv(MLoopUV *mloopuv, UVDataWrapper &uvs,
+ int start_index, COLLADAFW::IndexList& index_list, int count)
{
// per face vertex indices, this means for quad we have 4 indices, not 8
COLLADAFW::UIntValuesArray& indices = index_list.getIndices();
- uvs.getUV(indices[index + 0], mtface->uv[0]);
- uvs.getUV(indices[index + 1], mtface->uv[1]);
- uvs.getUV(indices[index + 2], mtface->uv[2]);
-
- if (quad) uvs.getUV(indices[index + 3], mtface->uv[3]);
-
-#ifdef COLLADA_DEBUG
- if (quad) {
- fprintf(stderr, "face uv:\n"
- "((%d, %d, %d, %d))\n"
- "((%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f))\n",
-
- indices[index + 0],
- indices[index + 1],
- indices[index + 2],
- indices[index + 3],
-
- mtface->uv[0][0], mtface->uv[0][1],
- mtface->uv[1][0], mtface->uv[1][1],
- mtface->uv[2][0], mtface->uv[2][1],
- mtface->uv[3][0], mtface->uv[3][1]);
+ for (int index = 0; index < count; index++) {
+ int uv_index = indices[index+start_index];
+ uvs.getUV(uv_index, mloopuv[index].uv);
}
- else {
- fprintf(stderr, "face uv:\n"
- "((%d, %d, %d))\n"
- "((%.1f, %.1f), (%.1f, %.1f), (%.1f, %.1f))\n",
-
- indices[index + 0],
- indices[index + 1],
- indices[index + 2],
-
- mtface->uv[0][0], mtface->uv[0][1],
- mtface->uv[1][0], mtface->uv[1][1],
- mtface->uv[2][0], mtface->uv[2][1]);
- }
-#endif
}
#ifdef COLLADA_DEBUG
@@ -329,91 +276,6 @@ void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me)
}
}
-int MeshImporter::triangulate_poly(unsigned int *indices, int totvert, MVert *verts, std::vector<unsigned int>& tri)
-{
- ListBase dispbase;
- DispList *dl;
- float *vert;
- int i = 0;
-
- dispbase.first = dispbase.last = NULL;
-
- dl = (DispList *)MEM_callocN(sizeof(DispList), "poly disp");
- dl->nr = totvert;
- dl->type = DL_POLY;
- dl->parts = 1;
- dl->verts = vert = (float *)MEM_callocN(totvert * 3 * sizeof(float), "poly verts");
- dl->index = (int *)MEM_callocN(sizeof(int) * 3 * totvert, "dl index");
-
- BLI_addtail(&dispbase, dl);
-
- for (i = 0; i < totvert; i++) {
- copy_v3_v3(vert, verts[indices[i]].co);
- vert += 3;
- }
-
- BKE_displist_fill(&dispbase, &dispbase, 0);
-
- int tottri = 0;
- dl = (DispList *)dispbase.first;
-
- if (dl->type == DL_INDEX3) {
- tottri = dl->parts;
-
- int *index = dl->index;
- for (i = 0; i < tottri; i++) {
- int t[3] = {*index, *(index + 1), *(index + 2)};
-
- std::sort(t, t + 3);
-
- tri.push_back(t[0]);
- tri.push_back(t[1]);
- tri.push_back(t[2]);
-
- index += 3;
- }
- }
-
- BKE_displist_free(&dispbase);
-
- return tottri;
-}
-
-int MeshImporter::count_new_tris(COLLADAFW::Mesh *mesh, Mesh *me)
-{
- COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
- unsigned int i;
- int tottri = 0;
-
- for (i = 0; i < prim_arr.getCount(); i++) {
-
- COLLADAFW::MeshPrimitive *mp = prim_arr[i];
- int type = mp->getPrimitiveType();
- size_t prim_totface = mp->getFaceCount();
- unsigned int *indices = mp->getPositionIndices().getData();
-
- if (type == COLLADAFW::MeshPrimitive::POLYLIST ||
- type == COLLADAFW::MeshPrimitive::POLYGONS)
- {
- COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
- COLLADAFW::Polygons::VertexCountArray& vcounta = mpvc->getGroupedVerticesVertexCountArray();
-
- for (unsigned int j = 0; j < prim_totface; j++) {
- int vcount = vcounta[j];
-
- if (vcount > 4) {
- std::vector<unsigned int> tri;
-
- // tottri += triangulate_poly(indices, vcount, me->mvert, tri) - 1; // XXX why - 1?!
- tottri += triangulate_poly(indices, vcount, me->mvert, tri);
- }
-
- indices += vcount;
- }
- }
- }
- return tottri;
-}
// =====================================================================
// condition 1: The Primitive has normals
@@ -471,10 +333,11 @@ bool MeshImporter::primitive_has_faces(COLLADAFW::MeshPrimitive *mp) {
// hint: This is done because mesh->getFacesCount() does
// count loose edges as extra faces, which is not what we want here.
// =================================================================
-void MeshImporter::allocate_face_data(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris)
+void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me)
{
- COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
- int total_facecount = 0;
+ COLLADAFW::MeshPrimitiveArray& prim_arr = collada_mesh->getMeshPrimitives();
+ int total_poly_count = 0;
+ int total_loop_count = 0;
// collect edge_count and face_count from all parts
for (int i = 0; i < prim_arr.getCount(); i++) {
@@ -485,21 +348,77 @@ void MeshImporter::allocate_face_data(COLLADAFW::Mesh *mesh, Mesh *me, int new_t
case COLLADAFW::MeshPrimitive::TRIANGLE_FANS:
case COLLADAFW::MeshPrimitive::POLYLIST:
case COLLADAFW::MeshPrimitive::POLYGONS: {
- size_t prim_totface = mp->getFaceCount();
- total_facecount += prim_totface;
+
+ COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
+ size_t prim_poly_count = mpvc->getFaceCount();
+
+ size_t prim_loop_count = 0;
+ for(int index=0; index < prim_poly_count; index++) {
+ prim_loop_count += get_vertex_count(mpvc, index);
+ }
+
+ total_poly_count += prim_poly_count;
+ total_loop_count += prim_loop_count;
break;
}
default: break;
}
}
- // allocate space for faces
- if (total_facecount > 0) {
- me->totface = total_facecount + new_tris;
- me->mface = (MFace *)CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
+ // Add the data containers
+ if (total_poly_count > 0) {
+ me->totpoly = total_poly_count;
+ me->totloop = total_loop_count;
+ me->mpoly = (MPoly *)CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, NULL, me->totpoly);
+ me->mloop = (MLoop *)CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CALLOC, NULL, me->totloop);
+
+ unsigned int totuvset = collada_mesh->getUVCoords().getInputInfosArray().getCount();
+ for (int i = 0; i < totuvset; i++) {
+ if (collada_mesh->getUVCoords().getLength(i) == 0) {
+ totuvset = 0;
+ break;
+ }
+ }
+
+ if (totuvset > 0) {
+ for (int i = 0; i < totuvset; i++) {
+ COLLADAFW::MeshVertexData::InputInfos *info = collada_mesh->getUVCoords().getInputInfosArray()[i];
+ COLLADAFW::String &uvname = info->mName;
+ int x = 0;
+ // Allocate space for UV_data
+ CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, uvname.c_str());
+ CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, uvname.c_str());
+ }
+ // activate the first uv map
+ me->mtpoly = (MTexPoly *)CustomData_get_layer_n(&me->pdata, CD_MTEXPOLY, 0);
+ me->mloopuv = (MLoopUV *) CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, 0);
+ }
}
}
+unsigned int MeshImporter::get_vertex_count(COLLADAFW::Polygons *mp, int index) {
+ int type = mp->getPrimitiveType();
+ int result;
+ switch (type) {
+ case COLLADAFW::MeshPrimitive::TRIANGLES:
+ case COLLADAFW::MeshPrimitive::TRIANGLE_FANS: {
+ result = 3;
+ break;
+ }
+ case COLLADAFW::MeshPrimitive::POLYLIST:
+ case COLLADAFW::MeshPrimitive::POLYGONS: {
+ result = mp->getGroupedVerticesVertexCountArray()[index];
+ break;
+ }
+ default: {
+ result = -1;
+ break;
+ }
+ }
+ return result;
+}
+
+
unsigned int MeshImporter::get_loose_edge_count(COLLADAFW::Mesh *mesh) {
COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
int loose_edge_count = 0;
@@ -606,256 +525,118 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
//
// TODO: import uv set names
// ========================================================================
-void MeshImporter::read_faces(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris) //TODO:: Refactor. Possibly replace by iterators
+void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
{
unsigned int i;
- allocate_face_data(mesh, me, new_tris);
-
- // allocate UV Maps
- unsigned int totuvset = mesh->getUVCoords().getInputInfosArray().getCount();
+ allocate_poly_data(collada_mesh, me);
- for (i = 0; i < totuvset; i++) {
- if (mesh->getUVCoords().getLength(i) == 0) {
- totuvset = 0;
- break;
- }
- }
-
- for (i = 0; i < totuvset; i++) {
- COLLADAFW::MeshVertexData::InputInfos *info = mesh->getUVCoords().getInputInfosArray()[i];
- CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_CALLOC, NULL, me->totface, info->mName.c_str());
- //this->set_layername_map[i] = CustomData_get_layer_name(&me->fdata, CD_MTFACE, i);
- }
-
- // activate the first uv map
- if (totuvset) me->mtface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, 0);
-
- UVDataWrapper uvs(mesh->getUVCoords());
-
-#ifdef COLLADA_DEBUG
- // uvs.print();
-#endif
+ UVDataWrapper uvs(collada_mesh->getUVCoords());
- MFace *mface = me->mface;
+ MPoly *mpoly = me->mpoly;
+ MLoop *mloop = me->mloop;
+ int loop_index = 0;
MaterialIdPrimitiveArrayMap mat_prim_map;
- int face_index = 0;
-
- COLLADAFW::MeshPrimitiveArray& prim_arr = mesh->getMeshPrimitives();
-
- COLLADAFW::MeshVertexData& nor = mesh->getNormals();
+ COLLADAFW::MeshPrimitiveArray& prim_arr = collada_mesh->getMeshPrimitives();
+ COLLADAFW::MeshVertexData& nor = collada_mesh->getNormals();
for (i = 0; i < prim_arr.getCount(); i++) {
COLLADAFW::MeshPrimitive *mp = prim_arr[i];
// faces
- size_t prim_totface = mp->getFaceCount();
- unsigned int *indices = mp->getPositionIndices().getData();
- unsigned int *nind = mp->getNormalIndices().getData();
+ size_t prim_totpoly = mp->getFaceCount();
+ unsigned int *position_indices = mp->getPositionIndices().getData();
+ unsigned int *normal_indices = mp->getNormalIndices().getData();
bool mp_has_normals = primitive_has_useable_normals(mp);
bool mp_has_faces = primitive_has_faces(mp);
- int type = mp->getPrimitiveType();
- int index = 0;
+ int collada_meshtype = mp->getPrimitiveType();
- // since we cannot set mface->mat_nr here, we store a portion of me->mface in Primitive
- Primitive prim = {mface, 0};
+ // since we cannot set mpoly->mat_nr here, we store a portion of me->mface in Primitive
+ Primitive prim = {mpoly, 0};
COLLADAFW::IndexListArray& index_list_array = mp->getUVCoordIndicesArray();
-#ifdef COLLADA_DEBUG
- /*
- fprintf(stderr, "Primitive %d:\n", i);
- for (unsigned int j = 0; j < totuvset; j++) {
- print_index_list(*index_list_array[j]);
- }
- */
-#endif
-
- if (type == COLLADAFW::MeshPrimitive::TRIANGLES) {
- for (unsigned int j = 0; j < prim_totface; j++) {
-
- set_face_indices(mface, indices, false);
- indices += 3;
-
-#if 0
- for (unsigned int k = 0; k < totuvset; k++) {
- if (!index_list_array.empty() && index_list_array[k]) {
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
- set_face_uv(&mtface[face_index], uvs, k, *index_list_array[k], index, false);
- }
- }
-#else
- for (unsigned int k = 0; k < index_list_array.getCount(); k++) {
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
- set_face_uv(&mtface[face_index], uvs, *index_list_array[k], index, false);
- }
-#endif
-
- test_index_face(mface, &me->fdata, face_index, 3);
-
- if (mp_has_normals) {
- if (!flat_face(nind, nor, 3))
- mface->flag |= ME_SMOOTH;
-
- nind += 3;
- }
-
- index += 3;
- mface++;
- face_index++;
- prim.totface++;
- }
- }
-
// If MeshPrimitive is TRIANGLE_FANS we split it into triangles
// The first trifan vertex will be the first vertex in every triangle
- if (type == COLLADAFW::MeshPrimitive::TRIANGLE_FANS) {
+ // XXX The proper function of TRIANGLE_FANS is not tested!!!
+ // XXX In particular the handling of the normal_indices looks very wrong to me
+ if (collada_meshtype == COLLADAFW::MeshPrimitive::TRIANGLE_FANS) {
unsigned grouped_vertex_count = mp->getGroupedVertexElementsCount();
for (unsigned int group_index = 0; group_index < grouped_vertex_count; group_index++) {
- unsigned int first_vertex = indices[0]; // Store first trifan vertex
- unsigned int first_normal = nind[0]; // Store first trifan vertex normal
+ unsigned int first_vertex = position_indices[0]; // Store first trifan vertex
+ unsigned int first_normal = normal_indices[0]; // Store first trifan vertex normal
unsigned int vertex_count = mp->getGroupedVerticesVertexCount(group_index);
for (unsigned int vertex_index = 0; vertex_index < vertex_count - 2; vertex_index++) {
// For each triangle store indeces of its 3 vertices
- unsigned int triangle_vertex_indices[3] = {first_vertex, indices[1], indices[2]};
- set_face_indices(mface, triangle_vertex_indices, false);
- test_index_face(mface, &me->fdata, face_index, 3);
+ unsigned int triangle_vertex_indices[3] = {first_vertex, position_indices[1], position_indices[2]};
+ set_poly_indices(mpoly, mloop, loop_index, triangle_vertex_indices, 3);
if (mp_has_normals) { // vertex normals, same inplementation as for the triangles
// the same for vertces normals
- unsigned int vertex_normal_indices[3] = {first_normal, nind[1], nind[2]};
- if (!flat_face(vertex_normal_indices, nor, 3))
- mface->flag |= ME_SMOOTH;
- nind++;
+ unsigned int vertex_normal_indices[3] = {first_normal, normal_indices[1], normal_indices[2]};
+ if (!is_flat_face(vertex_normal_indices, nor, 3))
+ mpoly->flag |= ME_SMOOTH;
+ normal_indices++;
}
- mface++; // same inplementation as for the triangles
- indices++;
- face_index++;
- prim.totface++;
+ mpoly++;
+ mloop += 3;
+ loop_index += 3;
+ prim.totpoly++;
+
}
// Moving cursor to the next triangle fan.
if (mp_has_normals)
- nind += 2;
+ normal_indices += 2;
- indices += 2;
+ position_indices += 2;
}
}
- else if (type == COLLADAFW::MeshPrimitive::POLYLIST || type == COLLADAFW::MeshPrimitive::POLYGONS) {
- COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
- COLLADAFW::Polygons::VertexCountArray& vcounta = mpvc->getGroupedVerticesVertexCountArray();
- for (unsigned int j = 0; j < prim_totface; j++) {
+ if (collada_meshtype == COLLADAFW::MeshPrimitive::POLYLIST ||
+ collada_meshtype == COLLADAFW::MeshPrimitive::POLYGONS ||
+ collada_meshtype == COLLADAFW::MeshPrimitive::TRIANGLES) {
+ COLLADAFW::Polygons *mpvc = (COLLADAFW::Polygons *)mp;
+ for (unsigned int j = 0; j < prim_totpoly; j++) {
- // face
- int vcount = vcounta[j];
- if (vcount == 3 || vcount == 4) {
-
- set_face_indices(mface, indices, vcount == 4);
-
- // set mtface for each uv set
- // it is assumed that all primitives have equal number of UV sets
-
-#if 0
- for (unsigned int k = 0; k < totuvset; k++) {
- if (!index_list_array.empty() && index_list_array[k]) {
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
- set_face_uv(&mtface[face_index], uvs, k, *index_list_array[k], index, mface->v4 != 0);
- }
- }
-#else
- for (unsigned int k = 0; k < index_list_array.getCount(); k++) {
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, k);
- set_face_uv(&mtface[face_index], uvs, *index_list_array[k], index, vcount == 4);
- }
-#endif
+ // Vertices in polygon:
+ int vcount = get_vertex_count(mpvc, j);
+ set_poly_indices(mpoly, mloop, loop_index, position_indices, vcount);
- test_index_face(mface, &me->fdata, face_index, vcount);
- if (mp_has_normals) {
- if (!flat_face(nind, nor, vcount))
- mface->flag |= ME_SMOOTH;
+ for (unsigned int l = 0; l < index_list_array.getCount(); l++) {
+ int uvset_index = index_list_array[l]->getSetIndex();
- nind += vcount;
- }
-
- mface++;
- face_index++;
- prim.totface++;
-
- }
- else {
- std::vector<unsigned int> tri;
-
- triangulate_poly(indices, vcount, me->mvert, tri);
-
- for (unsigned int k = 0; k < tri.size() / 3; k++) {
- int v = k * 3;
- unsigned int uv_indices[3] = {
- index + tri[v],
- index + tri[v + 1],
- index + tri[v + 2]
- };
- unsigned int tri_indices[3] = {
- indices[tri[v]],
- indices[tri[v + 1]],
- indices[tri[v + 2]]
- };
-
- set_face_indices(mface, tri_indices, false);
-
-#if 0
- for (unsigned int l = 0; l < totuvset; l++) {
- if (!index_list_array.empty() && index_list_array[l]) {
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, l);
- set_face_uv(&mtface[face_index], uvs, l, *index_list_array[l], uv_indices);
- }
- }
-#else
- for (unsigned int l = 0; l < index_list_array.getCount(); l++) {
- int uvset_index = index_list_array[l]->getSetIndex();
-
- // get mtface by face index and uv set index
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&me->fdata, CD_MTFACE, uvset_index);
- set_face_uv(&mtface[face_index], uvs, *index_list_array[l], uv_indices);
- }
-#endif
-
-
- test_index_face(mface, &me->fdata, face_index, 3);
-
- if (mp_has_normals) {
- unsigned int ntri[3] = {nind[tri[v]], nind[tri[v + 1]], nind[tri[v + 2]]};
+ // get mtface by face index and uv set index
+ MLoopUV *mloopuv = (MLoopUV *)CustomData_get_layer_n(&me->ldata, CD_MLOOPUV, uvset_index);
- if (!flat_face(ntri, nor, 3))
- mface->flag |= ME_SMOOTH;
- }
-
- mface++;
- face_index++;
- prim.totface++;
- }
+ set_face_uv(mloopuv+loop_index, uvs, loop_index, *index_list_array[l], vcount);
+ }
- if (mp_has_normals)
- nind += vcount;
+ if (mp_has_normals) {
+ if (!is_flat_face(normal_indices, nor, vcount))
+ mpoly->flag |= ME_SMOOTH;
}
+
+ mpoly++;
+ mloop += vcount;
+ loop_index += vcount;
+ prim.totpoly++;
+
+ if (mp_has_normals)
+ normal_indices += vcount;
- index += vcount;
- indices += vcount;
+ position_indices += vcount;
}
}
- else if (type == COLLADAFW::MeshPrimitive::LINES) {
+
+ else if (collada_meshtype == COLLADAFW::MeshPrimitive::LINES) {
continue; // read the lines later after all the rest is done
}
@@ -863,7 +644,7 @@ void MeshImporter::read_faces(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris) //T
mat_prim_map[mp->getMaterialId()].push_back(prim);
}
- geom_uid_mat_mapping_map[mesh->getUniqueId()] = mat_prim_map;
+ geom_uid_mat_mapping_map[collada_mesh->getUniqueId()] = mat_prim_map;
}
void MeshImporter::get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i, int stride)
@@ -896,8 +677,7 @@ void MeshImporter::get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i,
break;
}
}
-
-bool MeshImporter::flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count)
+bool MeshImporter::is_flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count)
{
float a[3], b[3];
@@ -919,8 +699,6 @@ bool MeshImporter::flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor,
return true;
}
-MeshImporter::MeshImporter(UnitConverter *unitconv, ArmatureImporter *arm, Scene *sce) : unitconverter(unitconv), scene(sce), armature_importer(arm) {
-}
void MeshImporter::bmeshConversion()
{
@@ -929,10 +707,9 @@ void MeshImporter::bmeshConversion()
{
if ((*m).second) {
Mesh *me = (*m).second;
- BKE_mesh_convert_mfaces_to_mpolys(me);
BKE_mesh_tessface_clear(me);
-
BKE_mesh_calc_normals_mapping(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL);
+ //BKE_mesh_validate(me, 1);
}
}
}
@@ -1137,9 +914,10 @@ void MeshImporter::optimize_material_assignements()
MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial,
std::map<COLLADAFW::UniqueId, Material *>& uid_material_map,
Object *ob, const COLLADAFW::UniqueId *geom_uid,
- MTex **color_texture, char *layername, MTFace *texture_face,
+ char *layername, MTFace *texture_face,
std::map<Material *, TexIndexTextureArrayMap>& material_texture_mapping_map, short mat_index)
{
+ MTex *color_texture = NULL;
Mesh *me = (Mesh *)ob->data;
const COLLADAFW::UniqueId& ma_uid = cmaterial.getReferencedMaterial();
@@ -1167,17 +945,17 @@ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmateri
// loop through <bind_vertex_inputs>
for (i = 0; i < tex_array.getCount(); i++) {
- *color_texture = assign_textures_to_uvlayer(tex_array[i], me, texindex_texarray_map,
- *color_texture);
+ color_texture = assign_textures_to_uvlayer(tex_array[i], me, texindex_texarray_map,
+ color_texture);
}
// set texture face
- if (*color_texture &&
- strlen((*color_texture)->uvname) &&
- strcmp(layername, (*color_texture)->uvname) != 0) {
+ if (color_texture &&
+ strlen((color_texture)->uvname) &&
+ strcmp(layername, color_texture->uvname) != 0) {
texture_face = (MTFace *)CustomData_get_layer_named(&me->fdata, CD_MTFACE,
- (*color_texture)->uvname);
- strcpy(layername, (*color_texture)->uvname);
+ color_texture->uvname);
+ strcpy(layername, color_texture->uvname);
}
MaterialIdPrimitiveArrayMap& mat_prim_map = geom_uid_mat_mapping_map[*geom_uid];
@@ -1192,19 +970,18 @@ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmateri
for (it = prims.begin(); it != prims.end(); it++) {
Primitive& prim = *it;
- MFace *mface = prim.mface;
+ MPoly *mpoly = prim.mpoly;
- for (i = 0; i < prim.totface; i++, mface++) {
- mface->mat_nr = mat_index;
+ for (i = 0; i < prim.totpoly; i++, mpoly++) {
+ mpoly->mat_nr = mat_index;
// bind texture images to faces
- if (texture_face && (*color_texture)) {
- texture_face->tpage = (Image *)(*color_texture)->tex->ima;
+ if (texture_face && color_texture) {
+ texture_face->tpage = (Image *)color_texture->tex->ima;
texture_face++;
}
}
}
- }
-
+ }
return texture_face;
}
@@ -1251,15 +1028,15 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta
// replace ob->data freeing the old one
Mesh *old_mesh = (Mesh *)ob->data;
+ Mesh *new_mesh = uid_mesh_map[*geom_uid];
- set_mesh(ob, uid_mesh_map[*geom_uid]);
+ set_mesh(ob, new_mesh);
if (old_mesh->id.us == 0) BKE_libblock_free(&G.main->mesh, old_mesh);
char layername[100];
layername[0] = '\0';
MTFace *texture_face = NULL;
- MTex *color_texture = NULL;
COLLADAFW::MaterialBindingArray& mat_array =
geom->getMaterialBindings();
@@ -1269,7 +1046,7 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta
if (mat_array[i].getReferencedMaterial().isValid()) {
texture_face = assign_material_to_geom(mat_array[i], uid_material_map, ob, geom_uid,
- &color_texture, layername, texture_face,
+ layername, texture_face,
material_texture_mapping_map, i);
}
else {
@@ -1283,11 +1060,7 @@ Object *MeshImporter::create_mesh_object(COLLADAFW::Node *node, COLLADAFW::Insta
// create a mesh storing a pointer in a map so it can be retrieved later by geometry UID
bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom)
{
- // TODO: import also uvs, normals
- // XXX what to do with normal indices?
- // XXX num_normals may be != num verts, then what to do?
- // check geometry->getType() first
if (geom->getType() != COLLADAFW::Geometry::GEO_TYPE_MESH) {
// TODO: report warning
fprintf(stderr, "Mesh type %s is not supported\n", bc_geomTypeToStr(geom->getType()));
@@ -1306,23 +1079,16 @@ bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom)
me->id.us--; // is already 1 here, but will be set later in set_mesh
// 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)
this->uid_mesh_map[mesh->getUniqueId()] = me;
- // needed to map mesh to its geometry name (needed for shape key naming)
this->mesh_geom_map[std::string(me->id.name)] = str_geom_id;
-
- int new_tris = 0;
read_vertices(mesh, me);
-
- new_tris = count_new_tris(mesh, me);
-
- read_faces(mesh, me, new_tris);
-
- BKE_mesh_make_edges(me, 0);
+ read_polys(mesh, me);
+ BKE_mesh_calc_edges(me, 0);
// read_lines() must be called after the face edges have been generated.
// Oterwise the loose edges will be silently deleted again.
read_lines(mesh, me);
-
return true;
}
diff --git a/source/blender/collada/MeshImporter.h b/source/blender/collada/MeshImporter.h
index 8b0f5cdc200..751e6faf02b 100644
--- a/source/blender/collada/MeshImporter.h
+++ b/source/blender/collada/MeshImporter.h
@@ -31,6 +31,7 @@
#include <vector>
#include "COLLADAFWIndexList.h"
+#include "COLLADAFWPolygons.h"
#include "COLLADAFWInstanceGeometry.h"
#include "COLLADAFWMaterialBinding.h"
#include "COLLADAFWMesh.h"
@@ -89,30 +90,28 @@ private:
std::map<COLLADAFW::UniqueId, Mesh*> uid_mesh_map; // geometry unique id-to-mesh map
std::map<COLLADAFW::UniqueId, Object*> uid_object_map; // geom uid-to-object
std::vector<Object*> imported_objects; // list of imported objects
- // this structure is used to assign material indices to faces
+
+ // this structure is used to assign material indices to polygons
// it holds a portion of Mesh faces and corresponds to a DAE primitive list (<triangles>, <polylist>, etc.)
struct Primitive {
- MFace *mface;
- unsigned int totface;
+ MPoly *mpoly;
+ unsigned int totpoly;
};
typedef std::map<COLLADAFW::MaterialId, std::vector<Primitive> > MaterialIdPrimitiveArrayMap;
std::map<COLLADAFW::UniqueId, MaterialIdPrimitiveArrayMap> geom_uid_mat_mapping_map; // crazy name!
std::multimap<COLLADAFW::UniqueId, COLLADAFW::UniqueId> materials_mapped_to_geom; //< materials that have already been mapped to a geometry. A pair of geom uid and mat uid, one geometry can have several materials
-
- void set_face_indices(MFace *mface, unsigned int *indices, bool quad);
-
- // not used anymore, test_index_face from blenkernel is better
-#if 0
- // change face indices order so that v4 is not 0
- void rotate_face_indices(MFace *mface);
-#endif
-
- void set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
- COLLADAFW::IndexList& index_list, unsigned int *tris_indices);
-
- void set_face_uv(MTFace *mtface, UVDataWrapper &uvs,
- COLLADAFW::IndexList& index_list, int index, bool quad);
+ void set_poly_indices(MPoly *mpoly,
+ MLoop *mloop,
+ int loop_index,
+ unsigned int *indices,
+ int loop_count);
+
+ void set_face_uv(MLoopUV *mloopuv,
+ UVDataWrapper &uvs,
+ int loop_index,
+ COLLADAFW::IndexList& index_list,
+ int count);
#ifdef COLLADA_DEBUG
void print_index_list(COLLADAFW::IndexList& index_list);
@@ -121,11 +120,7 @@ private:
bool is_nice_mesh(COLLADAFW::Mesh *mesh);
void read_vertices(COLLADAFW::Mesh *mesh, Mesh *me);
-
- int triangulate_poly(unsigned int *indices, int totvert, MVert *verts, std::vector<unsigned int>& tri);
-
- int count_new_tris(COLLADAFW::Mesh *mesh, Mesh *me);
-
+
bool primitive_has_useable_normals(COLLADAFW::MeshPrimitive *mp);
bool primitive_has_faces(COLLADAFW::MeshPrimitive *mp);
@@ -135,15 +130,16 @@ private:
CustomData create_edge_custom_data(EdgeHash *eh);
- void allocate_face_data(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris);
+ void allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me);
// TODO: import uv set names
- void read_faces(COLLADAFW::Mesh *mesh, Mesh *me, int new_tris);
+ void read_polys(COLLADAFW::Mesh *mesh, Mesh *me);
void read_lines(COLLADAFW::Mesh *mesh, Mesh *me);
+ unsigned int get_vertex_count(COLLADAFW::Polygons *mp, int index);
void get_vector(float v[3], COLLADAFW::MeshVertexData& arr, int i, int stride);
- bool flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count);
+ bool is_flat_face(unsigned int *nind, COLLADAFW::MeshVertexData& nor, int count);
std::vector<Object *> get_all_users_of(Mesh *reference_mesh);
@@ -166,7 +162,7 @@ public:
MTFace *assign_material_to_geom(COLLADAFW::MaterialBinding cmaterial,
std::map<COLLADAFW::UniqueId, Material*>& uid_material_map,
Object *ob, const COLLADAFW::UniqueId *geom_uid,
- MTex **color_texture, char *layername, MTFace *texture_face,
+ char *layername, MTFace *texture_face,
std::map<Material*, TexIndexTextureArrayMap>& material_texture_mapping_map, short mat_index);
diff --git a/source/blender/collada/SConscript b/source/blender/collada/SConscript
index 18ef62e6c85..4da99a21517 100644
--- a/source/blender/collada/SConscript
+++ b/source/blender/collada/SConscript
@@ -33,9 +33,9 @@ defs = []
# TODO sanitize inc path building
# relative paths to include dirs, space-separated, string
if env['OURPLATFORM']=='darwin':
- incs = '../ikplugin ../../../intern/iksolver/extern ../blenlib ../blenkernel ../windowmanager ../blenloader ../makesdna ../makesrna ../editors/include ../imbuf ../../../intern/guardedalloc [OPENCOLLADA]/COLLADAStreamWriter [OPENCOLLADA]/COLLADABaseUtils [OPENCOLLADA]/COLLADAFramework [OPENCOLLADA]/COLLADASaxFrameworkLoader [OPENCOLLADA]/GeneratedSaxParser '.replace('[OPENCOLLADA]', env['BF_OPENCOLLADA_INC'])
+ incs = '../ikplugin ../../../intern/iksolver/extern ../blenlib ../blenkernel ../windowmanager ../blenloader ../makesdna ../makesrna ../editors/include ../imbuf ../bmesh ../../../intern/guardedalloc [OPENCOLLADA]/COLLADAStreamWriter [OPENCOLLADA]/COLLADABaseUtils [OPENCOLLADA]/COLLADAFramework [OPENCOLLADA]/COLLADASaxFrameworkLoader [OPENCOLLADA]/GeneratedSaxParser '.replace('[OPENCOLLADA]', env['BF_OPENCOLLADA_INC'])
else:
- incs = '../ikplugin ../../../intern/iksolver/extern ../blenlib ../blenkernel ../windowmanager ../makesdna ../blenloader ../makesrna ../editors/include ../imbuf ../../../intern/guardedalloc [OPENCOLLADA]/COLLADAStreamWriter/include [OPENCOLLADA]/COLLADABaseUtils/include [OPENCOLLADA]/COLLADAFramework/include [OPENCOLLADA]/COLLADASaxFrameworkLoader/include [OPENCOLLADA]/GeneratedSaxParser/include '.replace('[OPENCOLLADA]', env['BF_OPENCOLLADA_INC'])
+ incs = '../ikplugin ../../../intern/iksolver/extern ../blenlib ../blenkernel ../windowmanager ../makesdna ../blenloader ../makesrna ../editors/include ../imbuf ../bmesh ../../../intern/guardedalloc [OPENCOLLADA]/COLLADAStreamWriter/include [OPENCOLLADA]/COLLADABaseUtils/include [OPENCOLLADA]/COLLADAFramework/include [OPENCOLLADA]/COLLADASaxFrameworkLoader/include [OPENCOLLADA]/GeneratedSaxParser/include '.replace('[OPENCOLLADA]', env['BF_OPENCOLLADA_INC'])
if env['BF_BUILDINFO']:
defs.append('WITH_BUILDINFO')
diff --git a/source/blender/collada/TransformReader.cpp b/source/blender/collada/TransformReader.cpp
index 67166d819a6..e0ba77e2554 100644
--- a/source/blender/collada/TransformReader.cpp
+++ b/source/blender/collada/TransformReader.cpp
@@ -46,30 +46,28 @@ void TransformReader::get_node_mat(float mat[4][4], COLLADAFW::Node *node, std::
COLLADAFW::Transformation *tm = node->getTransformations()[i];
COLLADAFW::Transformation::TransformationType type = tm->getTransformationType();
- if (type == COLLADAFW::Transformation::MATRIX) {
- // XXX why does this return and discard all following transformations?
- dae_matrix_to_mat4(tm, mat);
- return;
- }
- else {
- switch (type) {
- case COLLADAFW::Transformation::TRANSLATE:
- dae_translate_to_mat4(tm, cur);
- break;
- case COLLADAFW::Transformation::ROTATE:
- dae_rotate_to_mat4(tm, cur);
- break;
- case COLLADAFW::Transformation::SCALE:
- dae_scale_to_mat4(tm, cur);
- break;
- case COLLADAFW::Transformation::LOOKAT:
- case COLLADAFW::Transformation::SKEW:
- fprintf(stderr, "LOOKAT and SKEW transformations are not supported yet.\n");
- break;
- }
- copy_m4_m4(copy, mat);
- mult_m4_m4m4(mat, copy, cur);
+ switch (type) {
+ case COLLADAFW::Transformation::MATRIX:
+ // XXX why does this return and discard all following transformations?
+ dae_matrix_to_mat4(tm, mat);
+ return;
+ case COLLADAFW::Transformation::TRANSLATE:
+ dae_translate_to_mat4(tm, cur);
+ break;
+ case COLLADAFW::Transformation::ROTATE:
+ dae_rotate_to_mat4(tm, cur);
+ break;
+ case COLLADAFW::Transformation::SCALE:
+ dae_scale_to_mat4(tm, cur);
+ break;
+ case COLLADAFW::Transformation::LOOKAT:
+ case COLLADAFW::Transformation::SKEW:
+ fprintf(stderr, "LOOKAT and SKEW transformations are not supported yet.\n");
+ break;
}
+
+ copy_m4_m4(copy, mat);
+ mult_m4_m4m4(mat, copy, cur);
if (animation_map) {
// AnimationList that drives this Transformation
diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp
index b3c288c8fc5..e75123c1e76 100644
--- a/source/blender/collada/collada.cpp
+++ b/source/blender/collada/collada.cpp
@@ -75,6 +75,7 @@ int collada_export(Scene *sce,
int include_material_textures,
int use_texture_copies,
+ int triangulate,
int use_object_instantiation,
int sort_by_name,
int second_life)
@@ -106,6 +107,7 @@ int collada_export(Scene *sce,
export_settings.include_material_textures= include_material_textures != 0;
export_settings.use_texture_copies = use_texture_copies != 0;
+ export_settings.triangulate = triangulate != 0;
export_settings.use_object_instantiation = use_object_instantiation != 0;
export_settings.sort_by_name = sort_by_name != 0;
export_settings.second_life = second_life != 0;
diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h
index 2fa5b22bb15..642259da7fc 100644
--- a/source/blender/collada/collada.h
+++ b/source/blender/collada/collada.h
@@ -67,6 +67,7 @@ int collada_export(Scene *sce,
int include_material_textures,
int use_texture_copies,
+ int triangulate,
int use_object_instantiation,
int sort_by_name,
int second_life);
diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp
index f43878943c1..c56aa3fdaf0 100644
--- a/source/blender/collada/collada_utils.cpp
+++ b/source/blender/collada/collada_utils.cpp
@@ -56,6 +56,7 @@ extern "C" {
#include "WM_api.h" // XXX hrm, see if we can do without this
#include "WM_types.h"
+#include "bmesh.h"
}
float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsigned int index)
@@ -137,25 +138,38 @@ Object *bc_add_object(Scene *scene, int type, const char *name)
return ob;
}
-Mesh *bc_to_mesh_apply_modifiers(Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type)
+Mesh *bc_get_mesh_copy(Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate)
{
Mesh *tmpmesh;
CustomDataMask mask = CD_MASK_MESH;
DerivedMesh *dm = NULL;
- switch (export_mesh_type) {
- case BC_MESH_TYPE_VIEW: {
- dm = mesh_create_derived_view(scene, ob, mask);
- break;
- }
- case BC_MESH_TYPE_RENDER: {
- dm = mesh_create_derived_render(scene, ob, mask);
- break;
+ if(apply_modifiers) {
+ switch (export_mesh_type) {
+ case BC_MESH_TYPE_VIEW: {
+ dm = mesh_create_derived_view(scene, ob, mask);
+ break;
+ }
+ case BC_MESH_TYPE_RENDER: {
+ dm = mesh_create_derived_render(scene, ob, mask);
+ break;
+ }
}
}
+ else {
+ dm = mesh_create_derived((Mesh *)ob->data, ob, NULL);
+ }
tmpmesh = BKE_mesh_add(G.main, "ColladaMesh"); // name is not important here
DM_to_mesh(dm, tmpmesh, ob);
dm->release(dm);
+
+ if (triangulate) {
+ bc_triangulate_mesh(tmpmesh);
+ }
+
+ // XXX Not sure if we need that for ngon_export as well.
+ BKE_mesh_tessface_ensure(tmpmesh);
+
return tmpmesh;
}
@@ -366,3 +380,14 @@ void bc_match_scale(std::vector<Object *> *objects_done,
}
}
+
+void bc_triangulate_mesh(Mesh *me) {
+ bool use_beauty = false;
+ bool tag_only = false;
+
+ BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default);
+ BM_mesh_bm_from_me(bm, me, FALSE, 0);
+ BM_mesh_triangulate(bm, use_beauty, tag_only, NULL, NULL);
+ BM_mesh_bm_to_me(bm, me, FALSE);
+ BM_mesh_free(bm);
+}
diff --git a/source/blender/collada/collada_utils.h b/source/blender/collada/collada_utils.h
index 892b57e6a4a..f8e6f09e498 100644
--- a/source/blender/collada/collada_utils.h
+++ b/source/blender/collada/collada_utils.h
@@ -62,7 +62,7 @@ extern float bc_get_float_value(const COLLADAFW::FloatOrDoubleArray& array, unsi
extern int bc_test_parent_loop(Object *par, Object *ob);
extern int bc_set_parent(Object *ob, Object *par, bContext *C, bool is_parent_space = true);
extern Object *bc_add_object(Scene *scene, int type, const char *name);
-extern Mesh *bc_to_mesh_apply_modifiers(Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type);
+extern Mesh *bc_get_mesh_copy(Scene *scene, Object *ob, BC_export_mesh_type export_mesh_type, bool apply_modifiers, bool triangulate);
extern Object *bc_get_assigned_armature(Object *ob);
extern Object *bc_get_highest_selected_ancestor_or_self(LinkNode *export_set, Object *ob);
@@ -84,4 +84,24 @@ extern int bc_get_active_UVLayer(Object *ob);
extern std::string bc_replace_string(std::string data, const std::string& pattern, const std::string& replacement);
extern std::string bc_url_encode(std::string data);
extern void bc_match_scale(std::vector<Object *> *objects_done, Scene &sce, UnitConverter &unit_converter);
+
+extern void bc_triangulate_mesh(Mesh *me);
+
+
+class BCPolygonNormalsIndices
+{
+ std::vector<unsigned int> normal_indices;
+
+ public:
+
+ void add_index(unsigned int index) {
+ normal_indices.push_back(index);
+ }
+
+ unsigned int operator[](unsigned int i) {
+ return normal_indices[i];
+ }
+
+};
+
#endif
diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp
index 864d6f08311..e4dd72d79e9 100644
--- a/source/blender/compositor/nodes/COM_ImageNode.cpp
+++ b/source/blender/compositor/nodes/COM_ImageNode.cpp
@@ -25,6 +25,7 @@
#include "COM_ExecutionSystem.h"
#include "COM_ImageOperation.h"
#include "COM_MultilayerImageOperation.h"
+#include "COM_ConvertPremulToStraightOperation.h"
#include "BKE_node.h"
#include "BLI_utildefines.h"
@@ -72,6 +73,7 @@ void ImageNode::convertToOperations(ExecutionSystem *graph, CompositorContext *c
ImageUser *imageuser = (ImageUser *)editorNode->storage;
int framenumber = context->getFramenumber();
int numberOfOutputs = this->getNumberOfOutputSockets();
+ bool outputStraightAlpha = editorNode->custom1 & CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT;
BKE_image_user_frame_calc(imageuser, context->getFramenumber(), 0);
/* force a load, we assume iuser index will be set OK anyway */
@@ -138,7 +140,15 @@ void ImageNode::convertToOperations(ExecutionSystem *graph, CompositorContext *c
if (numberOfOutputs > 0) {
ImageOperation *operation = new ImageOperation();
if (outputImage->isConnected()) {
- outputImage->relinkConnections(operation->getOutputSocket());
+ if (outputStraightAlpha) {
+ NodeOperation *alphaConvertOperation = new ConvertPremulToStraightOperation();
+ addLink(graph, operation->getOutputSocket(0), alphaConvertOperation->getInputSocket(0));
+ outputImage->relinkConnections(alphaConvertOperation->getOutputSocket());
+ graph->addOperation(alphaConvertOperation);
+ }
+ else {
+ outputImage->relinkConnections(operation->getOutputSocket());
+ }
}
operation->setImage(image);
operation->setImageUser(imageuser);
diff --git a/source/blender/compositor/operations/COM_TranslateOperation.h b/source/blender/compositor/operations/COM_TranslateOperation.h
index d53c3e464fc..a638ae7ce69 100644
--- a/source/blender/compositor/operations/COM_TranslateOperation.h
+++ b/source/blender/compositor/operations/COM_TranslateOperation.h
@@ -33,8 +33,6 @@ private:
float m_deltaX;
float m_deltaY;
bool m_isDeltaSet;
- float m_relativeOffsetX;
- float m_relativeOffsetY;
float m_factorX;
float m_factorY;
public:
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index bc7b62df185..533420ad641 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -36,6 +36,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
@@ -3341,21 +3343,21 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
icon = ICON_VISIBLE_IPO_OFF;
if (ale->type == ANIMTYPE_FCURVE)
- tooltip = "Channel is visible in Graph Editor for editing";
+ tooltip = TIP_("Channel is visible in Graph Editor for editing");
else
- tooltip = "Channel(s) are visible in Graph Editor for editing";
+ tooltip = TIP_("Channels are visible in Graph Editor for editing");
break;
case ACHANNEL_SETTING_EXPAND: /* expanded triangle */
//icon = ((enabled)? ICON_TRIA_DOWN : ICON_TRIA_RIGHT);
icon = ICON_TRIA_RIGHT;
- tooltip = "Make channels grouped under this channel visible";
+ tooltip = TIP_("Make channels grouped under this channel visible");
break;
case ACHANNEL_SETTING_SOLO: /* NLA Tracks only */
//icon = ((enabled)? ICON_LAYER_ACTIVE : ICON_LAYER_USED);
icon = ICON_LAYER_USED;
- tooltip = "NLA Track is the only one evaluated for the AnimData block it belongs to";
+ tooltip = TIP_("NLA Track is the only one evaluated for the AnimData block it belongs to");
break;
/* --- */
@@ -3364,7 +3366,7 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
// TODO: what about when there's no protect needed?
//icon = ((enabled)? ICON_LOCKED : ICON_UNLOCKED);
icon = ICON_UNLOCKED;
- tooltip = "Editability of keyframes for this channel";
+ tooltip = TIP_("Editability of keyframes for this channel");
break;
case ACHANNEL_SETTING_MUTE: /* muted speaker */
@@ -3372,9 +3374,9 @@ static void draw_setting_widget(bAnimContext *ac, bAnimListElem *ale, bAnimChann
icon = ICON_MUTE_IPO_OFF;
if (ale->type == ALE_FCURVE)
- tooltip = "Does F-Curve contribute to result";
+ tooltip = TIP_("Does F-Curve contribute to result");
else
- tooltip = "Do channels contribute to result";
+ tooltip = TIP_("Do channels contribute to result");
break;
default:
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index cc2366affe6..dc0fba0930f 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -584,9 +584,9 @@ void ANIM_uiTemplate_fmodifier_draw(uiLayout *layout, ID *id, ListBase *modifier
/* name */
if (fmi)
- uiItemL(sub, fmi->name, ICON_NONE);
+ uiItemL(sub, IFACE_(fmi->name), ICON_NONE);
else
- uiItemL(sub, "<Unknown Modifier>", ICON_NONE);
+ uiItemL(sub, IFACE_("<Unknown Modifier>"), ICON_NONE);
/* right-align ------------------------------------------- */
sub = uiLayoutRow(row, TRUE);
diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt
index 2bd9956ef5a..d9555108733 100644
--- a/source/blender/editors/armature/CMakeLists.txt
+++ b/source/blender/editors/armature/CMakeLists.txt
@@ -36,16 +36,25 @@ set(INC_SYS
)
set(SRC
+ armature_add.c
+ armature_edit.c
+ armature_naming.c
armature_ops.c
- editarmature.c
+ armature_relations.c
+ armature_select.c
+ armature_skinning.c
+ armature_utils.c
editarmature_generate.c
editarmature_retarget.c
editarmature_sketch.c
meshlaplacian.c
- poseSlide.c
- poseUtils.c
- poselib.c
- poseobject.c
+ pose_edit.c
+ pose_lib.c
+ pose_group.c
+ pose_select.c
+ pose_slide.c
+ pose_transform.c
+ pose_utils.c
reeb.c
BIF_generate.h
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
new file mode 100644
index 00000000000..531c0551c87
--- /dev/null
+++ b/source/blender/editors/armature/armature_add.c
@@ -0,0 +1,849 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators and API's for creating bones
+ */
+
+/** \file blender/editors/armature/armature_add.c
+ * \ingroup edarmature
+ */
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BKE_action.h"
+#include "BKE_constraint.h"
+#include "BKE_context.h"
+#include "BKE_idprop.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "armature_intern.h"
+
+/* *************** Adding stuff in editmode *************** */
+
+/* default bone add, returns it selected, but without tail set */
+/* XXX should be used everywhere, now it mallocs bones still locally in functions */
+EditBone *ED_armature_edit_bone_add(bArmature *arm, const char *name)
+{
+ EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone");
+
+ BLI_strncpy(bone->name, name, sizeof(bone->name));
+ unique_editbone_name(arm->edbo, bone->name, NULL);
+
+ BLI_addtail(arm->edbo, bone);
+
+ bone->flag |= BONE_TIPSEL;
+ bone->weight = 1.0f;
+ bone->dist = 0.25f;
+ bone->xwidth = 0.1f;
+ bone->zwidth = 0.1f;
+ bone->ease1 = 1.0f;
+ bone->ease2 = 1.0f;
+ bone->rad_head = 0.10f;
+ bone->rad_tail = 0.05f;
+ bone->segments = 1;
+ bone->layer = arm->layer;
+
+ return bone;
+}
+
+/* v3d and rv3d are allowed to be NULL */
+void add_primitive_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d)
+{
+ Object *obedit = scene->obedit; // XXX get from context
+ bArmature *arm = obedit->data;
+ float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
+ EditBone *bone;
+
+ /* Get inverse point for head and orientation for tail */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d));
+
+ if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
+ copy_m3_m4(obmat, rv3d->viewmat);
+ else unit_m3(obmat);
+
+ copy_m3_m4(viewmat, obedit->obmat);
+ mul_m3_m3m3(totmat, obmat, viewmat);
+ invert_m3_m3(imat, totmat);
+
+ ED_armature_deselect_all(obedit, 0);
+
+ /* Create a bone */
+ bone = ED_armature_edit_bone_add(arm, "Bone");
+
+ arm->act_edbone = bone;
+
+ copy_v3_v3(bone->head, curs);
+
+ if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
+ add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1
+ else
+ add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z
+}
+
+
+/* previously addvert_armature */
+/* the ctrl-click method */
+static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ View3D *v3d;
+ bArmature *arm;
+ EditBone *ebone, *newbone, *flipbone;
+ float mat[3][3], imat[3][3];
+ const float *curs;
+ int a, to_root = 0;
+ Object *obedit;
+ Scene *scene;
+
+ scene = CTX_data_scene(C);
+ v3d = CTX_wm_view3d(C);
+ obedit = CTX_data_edit_object(C);
+ arm = obedit->data;
+
+ /* find the active or selected bone */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if (ebone->flag & BONE_TIPSEL || arm->act_edbone == ebone)
+ break;
+ }
+ }
+
+ if (ebone == NULL) {
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if (ebone->flag & BONE_ROOTSEL || arm->act_edbone == ebone)
+ break;
+ }
+ }
+ if (ebone == NULL)
+ return OPERATOR_CANCELLED;
+
+ to_root = 1;
+ }
+
+ ED_armature_deselect_all(obedit, 0);
+
+ /* we re-use code for mirror editing... */
+ flipbone = NULL;
+ if (arm->flag & ARM_MIRROR_EDIT)
+ flipbone = ED_armature_bone_get_mirrored(arm->edbo, ebone);
+
+ for (a = 0; a < 2; a++) {
+ if (a == 1) {
+ if (flipbone == NULL)
+ break;
+ else {
+ SWAP(EditBone *, flipbone, ebone);
+ }
+ }
+
+ newbone = ED_armature_edit_bone_add(arm, ebone->name);
+ arm->act_edbone = newbone;
+
+ if (to_root) {
+ copy_v3_v3(newbone->head, ebone->head);
+ newbone->rad_head = ebone->rad_tail;
+ newbone->parent = ebone->parent;
+ }
+ else {
+ copy_v3_v3(newbone->head, ebone->tail);
+ newbone->rad_head = ebone->rad_tail;
+ newbone->parent = ebone;
+ newbone->flag |= BONE_CONNECTED;
+ }
+
+ curs = give_cursor(scene, v3d);
+ copy_v3_v3(newbone->tail, curs);
+ sub_v3_v3v3(newbone->tail, newbone->tail, obedit->obmat[3]);
+
+ if (a == 1)
+ newbone->tail[0] = -newbone->tail[0];
+
+ copy_m3_m4(mat, obedit->obmat);
+ invert_m3_m3(imat, mat);
+ mul_m3_v3(imat, newbone->tail);
+
+ newbone->length = len_v3v3(newbone->head, newbone->tail);
+ newbone->rad_tail = newbone->length * 0.05f;
+ newbone->dist = newbone->length * 0.25f;
+
+ }
+
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+static int armature_click_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ /* TODO most of this code is copied from set3dcursor_invoke,
+ * it would be better to reuse code in set3dcursor_invoke */
+
+ /* temporarily change 3d cursor position */
+ Scene *scene;
+ ARegion *ar;
+ View3D *v3d;
+ float *fp, tvec[3], oldcurs[3], mval_f[2];
+ int retv;
+
+ scene = CTX_data_scene(C);
+ ar = CTX_wm_region(C);
+ v3d = CTX_wm_view3d(C);
+
+ fp = give_cursor(scene, v3d);
+
+ copy_v3_v3(oldcurs, fp);
+
+ VECCOPY2D(mval_f, event->mval);
+ ED_view3d_win_to_3d(ar, fp, mval_f, tvec);
+ copy_v3_v3(fp, tvec);
+
+ /* extrude to the where new cursor is and store the operation result */
+ retv = armature_click_extrude_exec(C, op);
+
+ /* restore previous 3d cursor position */
+ copy_v3_v3(fp, oldcurs);
+
+ return retv;
+}
+
+void ARMATURE_OT_click_extrude(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Click-Extrude";
+ ot->idname = "ARMATURE_OT_click_extrude";
+ ot->description = "Create a new bone going from the last selected joint to the mouse position";
+
+ /* api callbacks */
+ ot->invoke = armature_click_extrude_invoke;
+ ot->exec = armature_click_extrude_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+}
+
+/* adds an EditBone between the nominated locations (should be in the right space) */
+EditBone *add_points_bone(Object *obedit, float head[3], float tail[3])
+{
+ EditBone *ebo;
+
+ ebo = ED_armature_edit_bone_add(obedit->data, "Bone");
+
+ copy_v3_v3(ebo->head, head);
+ copy_v3_v3(ebo->tail, tail);
+
+ return ebo;
+}
+
+
+static EditBone *get_named_editbone(ListBase *edbo, char *name)
+{
+ EditBone *eBone;
+
+ if (name) {
+ for (eBone = edbo->first; eBone; eBone = eBone->next) {
+ if (!strcmp(name, eBone->name))
+ return eBone;
+ }
+ }
+
+ return NULL;
+}
+
+/* Call this before doing any duplications
+ * */
+void preEditBoneDuplicate(ListBase *editbones)
+{
+ EditBone *eBone;
+
+ /* clear temp */
+ for (eBone = editbones->first; eBone; eBone = eBone->next) {
+ eBone->temp = NULL;
+ }
+}
+
+/*
+ * Note: When duplicating cross objects, editbones here is the list of bones
+ * from the SOURCE object but ob is the DESTINATION object
+ * */
+void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Object *src_ob, Object *dst_ob)
+{
+ /* If an edit bone has been duplicated, lets
+ * update it's constraints if the subtarget
+ * they point to has also been duplicated
+ */
+ EditBone *oldtarget, *newtarget;
+ bPoseChannel *pchan;
+ bConstraint *curcon;
+ ListBase *conlist;
+
+ if ( (pchan = BKE_pose_channel_verify(dst_ob->pose, dupBone->name)) ) {
+ if ( (conlist = &pchan->constraints) ) {
+ for (curcon = conlist->first; curcon; curcon = curcon->next) {
+ /* does this constraint have a subtarget in
+ * this armature?
+ */
+ bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(curcon, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if ((ct->tar == src_ob) && (ct->subtarget[0])) {
+ ct->tar = dst_ob; /* update target */
+ oldtarget = get_named_editbone(editbones, ct->subtarget);
+ if (oldtarget) {
+ /* was the subtarget bone duplicated too? If
+ * so, update the constraint to point at the
+ * duplicate of the old subtarget.
+ */
+ if (oldtarget->temp) {
+ newtarget = (EditBone *) oldtarget->temp;
+ BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
+ }
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(curcon, &targets, 0);
+ }
+ }
+ }
+ }
+}
+
+void updateDuplicateSubtarget(EditBone *dupBone, ListBase *editbones, Object *ob)
+{
+ updateDuplicateSubtargetObjects(dupBone, editbones, ob, ob);
+}
+
+
+EditBone *duplicateEditBoneObjects(EditBone *curBone, const char *name, ListBase *editbones,
+ Object *src_ob, Object *dst_ob)
+{
+ EditBone *eBone = MEM_mallocN(sizeof(EditBone), "addup_editbone");
+
+ /* Copy data from old bone to new bone */
+ memcpy(eBone, curBone, sizeof(EditBone));
+
+ curBone->temp = eBone;
+ eBone->temp = curBone;
+
+ if (name != NULL) {
+ BLI_strncpy(eBone->name, name, sizeof(eBone->name));
+ }
+
+ unique_editbone_name(editbones, eBone->name, NULL);
+ BLI_addtail(editbones, eBone);
+
+ /* copy the ID property */
+ if (curBone->prop)
+ eBone->prop = IDP_CopyProperty(curBone->prop);
+
+ /* Lets duplicate the list of constraints that the
+ * current bone has.
+ */
+ if (src_ob->pose) {
+ bPoseChannel *chanold, *channew;
+
+ chanold = BKE_pose_channel_verify(src_ob->pose, curBone->name);
+ if (chanold) {
+ /* WARNING: this creates a new posechannel, but there will not be an attached bone
+ * yet as the new bones created here are still 'EditBones' not 'Bones'.
+ */
+ channew = BKE_pose_channel_verify(dst_ob->pose, eBone->name);
+
+ if (channew) {
+ BKE_pose_channel_copy_data(channew, chanold);
+ }
+ }
+ }
+
+ return eBone;
+}
+
+EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editbones, Object *ob)
+{
+ return duplicateEditBoneObjects(curBone, name, editbones, ob, ob);
+}
+
+/* previously adduplicate_armature */
+static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bArmature *arm;
+ EditBone *eBone = NULL;
+ EditBone *curBone;
+ EditBone *firstDup = NULL; /* The beginning of the duplicated bones in the edbo list */
+
+ Object *obedit = CTX_data_edit_object(C);
+ arm = obedit->data;
+
+ /* cancel if nothing selected */
+ if (CTX_DATA_COUNT(C, selected_bones) == 0)
+ return OPERATOR_CANCELLED;
+
+ ED_armature_sync_selection(arm->edbo); // XXX why is this needed?
+
+ preEditBoneDuplicate(arm->edbo);
+
+ /* Select mirrored bones */
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (EBONE_VISIBLE(arm, curBone)) {
+ if (curBone->flag & BONE_SELECTED) {
+ eBone = ED_armature_bone_get_mirrored(arm->edbo, curBone);
+ if (eBone)
+ eBone->flag |= BONE_SELECTED;
+ }
+ }
+ }
+ }
+
+
+ /* Find the selected bones and duplicate them as needed */
+ for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
+ if (EBONE_VISIBLE(arm, curBone)) {
+ if (curBone->flag & BONE_SELECTED) {
+
+ eBone = duplicateEditBone(curBone, curBone->name, arm->edbo, obedit);
+
+ if (!firstDup)
+ firstDup = eBone;
+
+ }
+ }
+ }
+
+ /* Run though the list and fix the pointers */
+ for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
+ if (EBONE_VISIBLE(arm, curBone)) {
+ if (curBone->flag & BONE_SELECTED) {
+ eBone = (EditBone *) curBone->temp;
+
+ if (!curBone->parent) {
+ /* If this bone has no parent,
+ * Set the duplicate->parent to NULL
+ */
+ eBone->parent = NULL;
+ }
+ else if (curBone->parent->temp) {
+ /* If this bone has a parent that was duplicated,
+ * Set the duplicate->parent to the curBone->parent->temp
+ */
+ eBone->parent = (EditBone *)curBone->parent->temp;
+ }
+ else {
+ /* If this bone has a parent that IS not selected,
+ * Set the duplicate->parent to the curBone->parent
+ */
+ eBone->parent = (EditBone *) curBone->parent;
+ eBone->flag &= ~BONE_CONNECTED;
+ }
+
+ /* Lets try to fix any constraint subtargets that might
+ * have been duplicated
+ */
+ updateDuplicateSubtarget(eBone, arm->edbo, obedit);
+ }
+ }
+ }
+
+ /* correct the active bone */
+ if (arm->act_edbone) {
+ eBone = arm->act_edbone;
+ if (eBone->temp)
+ arm->act_edbone = eBone->temp;
+ }
+
+ /* Deselect the old bones and select the new ones */
+ for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
+ if (EBONE_VISIBLE(arm, curBone))
+ curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+
+ ED_armature_validate_active(arm);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+
+void ARMATURE_OT_duplicate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Duplicate Selected Bone(s)";
+ ot->idname = "ARMATURE_OT_duplicate";
+ ot->description = "Make copies of the selected bones within the same armature";
+
+ /* api callbacks */
+ ot->exec = armature_duplicate_selected_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ------------------------------------------ */
+
+/* previously extrude_armature */
+/* context; editmode armature */
+/* if forked && mirror-edit: makes two bones with flipped names */
+static int armature_extrude_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ bArmature *arm;
+ EditBone *newbone, *ebone, *flipbone, *first = NULL;
+ int a, totbone = 0, do_extrude;
+ int forked = RNA_boolean_get(op->ptr, "forked");
+
+ obedit = CTX_data_edit_object(C);
+ arm = obedit->data;
+
+ /* since we allow root extrude too, we have to make sure selection is OK */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if (ebone->flag & BONE_ROOTSEL) {
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ if (ebone->parent->flag & BONE_TIPSEL)
+ ebone->flag &= ~BONE_ROOTSEL;
+ }
+ }
+ }
+ }
+
+ /* Duplicate the necessary bones */
+ for (ebone = arm->edbo->first; ((ebone) && (ebone != first)); ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ /* we extrude per definition the tip */
+ do_extrude = FALSE;
+ if (ebone->flag & (BONE_TIPSEL | BONE_SELECTED)) {
+ do_extrude = TRUE;
+ }
+ else if (ebone->flag & BONE_ROOTSEL) {
+ /* but, a bone with parent deselected we do the root... */
+ if (ebone->parent && (ebone->parent->flag & BONE_TIPSEL)) {
+ /* pass */
+ }
+ else {
+ do_extrude = 2;
+ }
+ }
+
+ if (do_extrude) {
+ /* we re-use code for mirror editing... */
+ flipbone = NULL;
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ flipbone = ED_armature_bone_get_mirrored(arm->edbo, ebone);
+ if (flipbone) {
+ forked = 0; // we extrude 2 different bones
+ if (flipbone->flag & (BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED))
+ /* don't want this bone to be selected... */
+ flipbone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ }
+ if ((flipbone == NULL) && (forked))
+ flipbone = ebone;
+ }
+
+ for (a = 0; a < 2; a++) {
+ if (a == 1) {
+ if (flipbone == NULL)
+ break;
+ else {
+ SWAP(EditBone *, flipbone, ebone);
+ }
+ }
+
+ totbone++;
+ newbone = MEM_callocN(sizeof(EditBone), "extrudebone");
+
+ if (do_extrude == TRUE) {
+ copy_v3_v3(newbone->head, ebone->tail);
+ copy_v3_v3(newbone->tail, newbone->head);
+ newbone->parent = ebone;
+
+ newbone->flag = ebone->flag & (BONE_TIPSEL | BONE_RELATIVE_PARENTING); // copies it, in case mirrored bone
+
+ if (newbone->parent) newbone->flag |= BONE_CONNECTED;
+ }
+ else {
+ copy_v3_v3(newbone->head, ebone->head);
+ copy_v3_v3(newbone->tail, ebone->head);
+ newbone->parent = ebone->parent;
+
+ newbone->flag = BONE_TIPSEL;
+
+ if (newbone->parent && (ebone->flag & BONE_CONNECTED)) {
+ newbone->flag |= BONE_CONNECTED;
+ }
+ }
+
+ newbone->weight = ebone->weight;
+ newbone->dist = ebone->dist;
+ newbone->xwidth = ebone->xwidth;
+ newbone->zwidth = ebone->zwidth;
+ newbone->ease1 = ebone->ease1;
+ newbone->ease2 = ebone->ease2;
+ newbone->rad_head = ebone->rad_tail; // don't copy entire bone...
+ newbone->rad_tail = ebone->rad_tail;
+ newbone->segments = 1;
+ newbone->layer = ebone->layer;
+
+ BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name));
+
+ if (flipbone && forked) { // only set if mirror edit
+ if (strlen(newbone->name) < 30) {
+ if (a == 0) strcat(newbone->name, "_L");
+ else strcat(newbone->name, "_R");
+ }
+ }
+ unique_editbone_name(arm->edbo, newbone->name, NULL);
+
+ /* Add the new bone to the list */
+ BLI_addtail(arm->edbo, newbone);
+ if (!first)
+ first = newbone;
+
+ /* restore ebone if we were flipping */
+ if (a == 1 && flipbone)
+ SWAP(EditBone *, flipbone, ebone);
+ }
+ }
+
+ /* Deselect the old bone */
+ ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ }
+ }
+ /* if only one bone, make this one active */
+ if (totbone == 1 && first) arm->act_edbone = first;
+
+ if (totbone == 0) return OPERATOR_CANCELLED;
+
+ /* Transform the endpoints */
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_extrude(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Extrude";
+ ot->idname = "ARMATURE_OT_extrude";
+ ot->description = "Create new bones from the selected joints";
+
+ /* api callbacks */
+ ot->exec = armature_extrude_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "forked", 0, "Forked", "");
+}
+
+/* ********************** Bone Add *************************************/
+
+/*op makes a new bone and returns it with its tip selected */
+
+static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
+{
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ Object *obedit = CTX_data_edit_object(C);
+ EditBone *bone;
+ float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
+ char name[MAXBONENAME];
+
+ RNA_string_get(op->ptr, "name", name);
+
+ copy_v3_v3(curs, give_cursor(CTX_data_scene(C), CTX_wm_view3d(C)));
+
+ /* Get inverse point for head and orientation for tail */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_m4_v3(obedit->imat, curs);
+
+ if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
+ copy_m3_m4(obmat, rv3d->viewmat);
+ else unit_m3(obmat);
+
+ copy_m3_m4(viewmat, obedit->obmat);
+ mul_m3_m3m3(totmat, obmat, viewmat);
+ invert_m3_m3(imat, totmat);
+
+ ED_armature_deselect_all(obedit, 0);
+
+ /* Create a bone */
+ bone = ED_armature_edit_bone_add(obedit->data, name);
+
+ copy_v3_v3(bone->head, curs);
+
+ if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
+ add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1
+ else
+ add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_bone_primitive_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Bone";
+ ot->idname = "ARMATURE_OT_bone_primitive_add";
+ ot->description = "Add a new bone located at the 3D-Cursor";
+
+ /* api callbacks */
+ ot->exec = armature_bone_primitive_add_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_string(ot->srna, "name", "Bone", MAXBONENAME, "Name", "Name of the newly created bone");
+
+}
+
+/* ********************** Subdivide *******************************/
+
+/* Subdivide Operators:
+ * This group of operators all use the same 'exec' callback, but they are called
+ * through several different operators - a combined menu (which just calls the exec in the
+ * appropriate ways), and two separate ones.
+ */
+
+static int armature_subdivide_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *newbone, *tbone;
+ int cuts, i;
+
+ /* there may not be a number_cuts property defined (for 'simple' subdivide) */
+ cuts = RNA_int_get(op->ptr, "number_cuts");
+
+ /* loop over all editable bones */
+ // XXX the old code did this in reverse order though!
+ CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
+ {
+ for (i = cuts + 1; i > 1; i--) {
+ /* compute cut ratio first */
+ float cutratio = 1.0f / (float)i;
+ float cutratioI = 1.0f - cutratio;
+
+ float val1[3];
+ float val2[3];
+ float val3[3];
+
+ newbone = MEM_mallocN(sizeof(EditBone), "ebone subdiv");
+ *newbone = *ebone;
+ BLI_addtail(arm->edbo, newbone);
+
+ /* calculate location of newbone->head */
+ copy_v3_v3(val1, ebone->head);
+ copy_v3_v3(val2, ebone->tail);
+ copy_v3_v3(val3, newbone->head);
+
+ val3[0] = val1[0] * cutratio + val2[0] * cutratioI;
+ val3[1] = val1[1] * cutratio + val2[1] * cutratioI;
+ val3[2] = val1[2] * cutratio + val2[2] * cutratioI;
+
+ copy_v3_v3(newbone->head, val3);
+ copy_v3_v3(newbone->tail, ebone->tail);
+ copy_v3_v3(ebone->tail, newbone->head);
+
+ newbone->rad_head = 0.5f * (ebone->rad_head + ebone->rad_tail);
+ ebone->rad_tail = newbone->rad_head;
+
+ newbone->flag |= BONE_CONNECTED;
+
+ unique_editbone_name(arm->edbo, newbone->name, NULL);
+
+ /* correct parent bones */
+ for (tbone = arm->edbo->first; tbone; tbone = tbone->next) {
+ if (tbone->parent == ebone)
+ tbone->parent = newbone;
+ }
+ newbone->parent = ebone;
+ }
+ }
+ CTX_DATA_END;
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_subdivide(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Subdivide Multi";
+ ot->idname = "ARMATURE_OT_subdivide";
+ ot->description = "Break selected bones into chains of smaller bones";
+
+ /* api callbacks */
+ ot->exec = armature_subdivide_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Properties */
+ prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10);
+ /* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
new file mode 100644
index 00000000000..12602c10955
--- /dev/null
+++ b/source/blender/editors/armature/armature_edit.c
@@ -0,0 +1,1245 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Armature EditMode tools - transforms, chain based editing, and other settings
+ */
+
+/** \file blender/editors/armature/armature_edit.c
+ * \ingroup edarmature
+ */
+
+#include <assert.h>
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_report.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "armature_intern.h"
+
+/* ************************** Object Tools Exports ******************************* */
+/* NOTE: these functions are exported to the Object module to be called from the tools there */
+
+void ED_armature_apply_transform(Object *ob, float mat[4][4])
+{
+ EditBone *ebone;
+ bArmature *arm = ob->data;
+ float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */
+ float mat3[3][3];
+
+ copy_m3_m4(mat3, mat);
+ normalize_m3(mat3);
+
+ /* Put the armature into editmode */
+ ED_armature_to_edit(ob);
+
+ /* Do the rotations */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ float delta[3], tmat[3][3];
+
+ /* find the current bone's roll matrix */
+ sub_v3_v3v3(delta, ebone->tail, ebone->head);
+ vec_roll_to_mat3(delta, ebone->roll, tmat);
+
+ /* transform the roll matrix */
+ mul_m3_m3m3(tmat, mat3, tmat);
+
+ /* transform the bone */
+ mul_m4_v3(mat, ebone->head);
+ mul_m4_v3(mat, ebone->tail);
+
+ /* apply the transfiormed roll back */
+ mat3_to_vec_roll(tmat, NULL, &ebone->roll);
+
+ ebone->rad_head *= scale;
+ ebone->rad_tail *= scale;
+ ebone->dist *= scale;
+
+ /* we could be smarter and scale by the matrix along the x & z axis */
+ ebone->xwidth *= scale;
+ ebone->zwidth *= scale;
+ }
+
+ /* Turn the list into an armature */
+ ED_armature_from_edit(ob);
+ ED_armature_edit_free(ob);
+}
+
+/* exported for use in editors/object/ */
+/* 0 == do center, 1 == center new, 2 == center cursor */
+void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int centermode, int around)
+{
+ Object *obedit = scene->obedit; // XXX get from context
+ EditBone *ebone;
+ bArmature *arm = ob->data;
+ float cent[3];
+
+ /* Put the armature into editmode */
+ if (ob != obedit) {
+ ED_armature_to_edit(ob);
+ obedit = NULL; /* we cant use this so behave as if there is no obedit */
+ }
+
+ /* Find the centerpoint */
+ if (centermode == 2) {
+ copy_v3_v3(cent, cursor);
+ invert_m4_m4(ob->imat, ob->obmat);
+ mul_m4_v3(ob->imat, cent);
+ }
+ else {
+ if (around == V3D_CENTROID) {
+ int total = 0;
+ zero_v3(cent);
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ total += 2;
+ add_v3_v3(cent, ebone->head);
+ add_v3_v3(cent, ebone->tail);
+ }
+ if (total) {
+ mul_v3_fl(cent, 1.0f / (float)total);
+ }
+ }
+ else {
+ float min[3], max[3];
+ INIT_MINMAX(min, max);
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ minmax_v3v3_v3(min, max, ebone->head);
+ minmax_v3v3_v3(min, max, ebone->tail);
+ }
+ mid_v3_v3v3(cent, min, max);
+ }
+ }
+
+ /* Do the adjustments */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ sub_v3_v3(ebone->head, cent);
+ sub_v3_v3(ebone->tail, cent);
+ }
+
+ /* Turn the list into an armature */
+ if (obedit == NULL) {
+ ED_armature_from_edit(ob);
+ ED_armature_edit_free(ob);
+ }
+
+ /* Adjust object location for new centerpoint */
+ if (centermode && obedit == NULL) {
+ mul_mat3_m4_v3(ob->obmat, cent); /* ommit translation part */
+ add_v3_v3(ob->loc, cent);
+ }
+}
+
+/* ********************************* Roll ******************************* */
+
+/* adjust bone roll to align Z axis with vector
+ * vec is in local space and is normalized
+ */
+float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const short axis_only)
+{
+ float mat[3][3], nor[3];
+
+ sub_v3_v3v3(nor, bone->tail, bone->head);
+ vec_roll_to_mat3(nor, 0.0f, mat);
+
+ /* check the bone isn't aligned with the axis */
+ if (!is_zero_v3(align_axis) && angle_v3v3(align_axis, mat[2]) > FLT_EPSILON) {
+ float vec[3], align_axis_proj[3], roll;
+
+ /* project the new_up_axis along the normal */
+ project_v3_v3v3(vec, align_axis, nor);
+ sub_v3_v3v3(align_axis_proj, align_axis, vec);
+
+ if (axis_only) {
+ if (angle_v3v3(align_axis_proj, mat[2]) > (float)(M_PI / 2.0)) {
+ negate_v3(align_axis_proj);
+ }
+ }
+
+ roll = angle_v3v3(align_axis_proj, mat[2]);
+
+ cross_v3_v3v3(vec, mat[2], align_axis_proj);
+
+ if (dot_v3v3(vec, nor) < 0) {
+ roll = -roll;
+ }
+
+ return roll;
+ }
+
+ return 0.0f;
+}
+
+
+typedef enum eCalcRollTypes {
+ CALC_ROLL_X = 0,
+ CALC_ROLL_Y = 1,
+ CALC_ROLL_Z = 2,
+
+ CALC_ROLL_ACTIVE = 5,
+ CALC_ROLL_VIEW = 6,
+ CALC_ROLL_CURSOR = 7
+} eCalcRollTypes;
+
+static EnumPropertyItem prop_calc_roll_types[] = {
+ {CALC_ROLL_X, "X", 0, "X Axis", ""},
+ {CALC_ROLL_Y, "Y", 0, "Y Axis", ""},
+ {CALC_ROLL_Z, "Z", 0, "Z Axis", ""},
+ {CALC_ROLL_ACTIVE, "ACTIVE", 0, "Active Bone", ""},
+ {CALC_ROLL_VIEW, "VIEW", 0, "View Axis", ""},
+ {CALC_ROLL_CURSOR, "CURSOR", 0, "Cursor", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+
+static int armature_calc_roll_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ const short type = RNA_enum_get(op->ptr, "type");
+ const short axis_only = RNA_boolean_get(op->ptr, "axis_only");
+ const short axis_flip = RNA_boolean_get(op->ptr, "axis_flip");
+
+ float imat[3][3];
+
+ bArmature *arm = ob->data;
+ EditBone *ebone;
+
+ copy_m3_m4(imat, ob->obmat);
+ invert_m3(imat);
+
+ if (type == CALC_ROLL_CURSOR) { /* Cursor */
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C); /* can be NULL */
+ float cursor_local[3];
+ const float *cursor = give_cursor(scene, v3d);
+
+
+ copy_v3_v3(cursor_local, cursor);
+ mul_m3_v3(imat, cursor_local);
+
+ /* cursor */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
+ float cursor_rel[3];
+ sub_v3_v3v3(cursor_rel, cursor_local, ebone->head);
+ if (axis_flip) negate_v3(cursor_rel);
+ ebone->roll = ED_rollBoneToVector(ebone, cursor_rel, axis_only);
+ }
+ }
+ }
+ else {
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+ if (type == CALC_ROLL_VIEW) { /* View */
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No region view3d available");
+ return OPERATOR_CANCELLED;
+ }
+
+ copy_v3_v3(vec, rv3d->viewinv[2]);
+ mul_m3_v3(imat, vec);
+ }
+ else if (type == CALC_ROLL_ACTIVE) {
+ float mat[3][3], nor[3];
+ ebone = (EditBone *)arm->act_edbone;
+ if (ebone == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "No active bone set");
+ return OPERATOR_CANCELLED;
+ }
+
+ sub_v3_v3v3(nor, ebone->tail, ebone->head);
+ vec_roll_to_mat3(nor, ebone->roll, mat);
+ copy_v3_v3(vec, mat[2]);
+ }
+ else { /* Axis */
+ assert(type >= 0 && type <= 5);
+ if (type < 3) vec[type] = 1.0f;
+ else vec[type - 2] = -1.0f;
+ mul_m3_v3(imat, vec);
+ }
+
+ if (axis_flip) negate_v3(vec);
+
+ 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 = ED_rollBoneToVector(ebone, vec, axis_only);
+ }
+ }
+ }
+
+ 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_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_calculate_roll(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Recalculate Roll";
+ ot->idname = "ARMATURE_OT_calculate_roll";
+ ot->description = "Automatically fix alignment of select bones' axes";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_calc_roll_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, 0, "Type", "");
+ RNA_def_boolean(ot->srna, "axis_flip", 0, "Flip Axis", "Negate the alignment axis");
+ RNA_def_boolean(ot->srna, "axis_only", 0, "Shortest Rotation", "Ignore the axis direction, use the shortest rotation to align");
+}
+
+/* ******************************** Chain-Based Tools ********************************* */
+
+/* temporary data-structure for merge/fill bones */
+typedef struct EditBonePoint {
+ struct EditBonePoint *next, *prev;
+
+ EditBone *head_owner; /* EditBone which uses this point as a 'head' point */
+ EditBone *tail_owner; /* EditBone which uses this point as a 'tail' point */
+
+ float vec[3]; /* the actual location of the point in local/EditMode space */
+} EditBonePoint;
+
+/* find chain-tips (i.e. bones without children) */
+static void chains_find_tips(ListBase *edbo, ListBase *list)
+{
+ EditBone *curBone, *ebo;
+ LinkData *ld;
+
+ /* note: this is potentially very slow ... there's got to be a better way */
+ for (curBone = edbo->first; curBone; curBone = curBone->next) {
+ short stop = 0;
+
+ /* is this bone contained within any existing chain? (skip if so) */
+ for (ld = list->first; ld; ld = ld->next) {
+ for (ebo = ld->data; ebo; ebo = ebo->parent) {
+ if (ebo == curBone) {
+ stop = 1;
+ break;
+ }
+ }
+
+ if (stop) break;
+ }
+ /* skip current bone if it is part of an existing chain */
+ if (stop) continue;
+
+ /* is any existing chain part of the chain formed by this bone? */
+ stop = 0;
+ for (ebo = curBone->parent; ebo; ebo = ebo->parent) {
+ for (ld = list->first; ld; ld = ld->next) {
+ if (ld->data == ebo) {
+ ld->data = curBone;
+ stop = 1;
+ break;
+ }
+ }
+
+ if (stop) break;
+ }
+ /* current bone has already been added to a chain? */
+ if (stop) continue;
+
+ /* add current bone to a new chain */
+ ld = MEM_callocN(sizeof(LinkData), "BoneChain");
+ ld->data = curBone;
+ BLI_addtail(list, ld);
+ }
+}
+
+/* --------------------- */
+
+static void fill_add_joint(EditBone *ebo, short eb_tail, ListBase *points)
+{
+ EditBonePoint *ebp;
+ float vec[3];
+ short found = 0;
+
+ if (eb_tail) {
+ copy_v3_v3(vec, ebo->tail);
+ }
+ else {
+ copy_v3_v3(vec, ebo->head);
+ }
+
+ for (ebp = points->first; ebp; ebp = ebp->next) {
+ if (equals_v3v3(ebp->vec, vec)) {
+ if (eb_tail) {
+ if ((ebp->head_owner) && (ebp->head_owner->parent == ebo)) {
+ /* so this bone's tail owner is this bone */
+ ebp->tail_owner = ebo;
+ found = 1;
+ break;
+ }
+ }
+ else {
+ if ((ebp->tail_owner) && (ebo->parent == ebp->tail_owner)) {
+ /* so this bone's head owner is this bone */
+ ebp->head_owner = ebo;
+ found = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ /* allocate a new point if no existing point was related */
+ if (found == 0) {
+ ebp = MEM_callocN(sizeof(EditBonePoint), "EditBonePoint");
+
+ if (eb_tail) {
+ copy_v3_v3(ebp->vec, ebo->tail);
+ ebp->tail_owner = ebo;
+ }
+ else {
+ copy_v3_v3(ebp->vec, ebo->head);
+ ebp->head_owner = ebo;
+ }
+
+ BLI_addtail(points, ebp);
+ }
+}
+
+/* bone adding between selected joints */
+static int armature_fill_bones_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = (obedit) ? obedit->data : NULL;
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ ListBase points = {NULL, NULL};
+ int count;
+
+ /* sanity checks */
+ if (ELEM(NULL, obedit, arm))
+ return OPERATOR_CANCELLED;
+
+ /* loop over all bones, and only consider if visible */
+ CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
+ {
+ if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL))
+ fill_add_joint(ebone, 0, &points);
+ if (ebone->flag & BONE_TIPSEL)
+ fill_add_joint(ebone, 1, &points);
+ }
+ CTX_DATA_END;
+
+ /* the number of joints determines how we fill:
+ * 1) between joint and cursor (joint=head, cursor=tail)
+ * 2) between the two joints (order is dependent on active-bone/hierachy)
+ * 3+) error (a smarter method involving finding chains needs to be worked out
+ */
+ count = BLI_countlist(&points);
+
+ if (count == 0) {
+ BKE_report(op->reports, RPT_ERROR, "No joints selected");
+ return OPERATOR_CANCELLED;
+ }
+ else if (count == 1) {
+ EditBonePoint *ebp;
+ float curs[3];
+
+ /* Get Points - selected joint */
+ ebp = (EditBonePoint *)points.first;
+
+ /* Get points - cursor (tail) */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d));
+
+ /* Create a bone */
+ /* newbone = */ add_points_bone(obedit, ebp->vec, curs);
+ }
+ else if (count == 2) {
+ EditBonePoint *ebp, *ebp2;
+ float head[3], tail[3];
+ short headtail = 0;
+
+ /* check that the points don't belong to the same bone */
+ ebp = (EditBonePoint *)points.first;
+ ebp2 = ebp->next;
+
+ if ((ebp->head_owner == ebp2->tail_owner) && (ebp->head_owner != NULL)) {
+ BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
+ BLI_freelistN(&points);
+ return OPERATOR_CANCELLED;
+ }
+ if ((ebp->tail_owner == ebp2->head_owner) && (ebp->tail_owner != NULL)) {
+ BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
+ BLI_freelistN(&points);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* find which one should be the 'head' */
+ if ((ebp->head_owner && ebp2->head_owner) || (ebp->tail_owner && ebp2->tail_owner)) {
+ /* rule: whichever one is closer to 3d-cursor */
+ float curs[3];
+ float vecA[3], vecB[3];
+ float distA, distB;
+
+ /* get cursor location */
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d));
+
+ /* get distances */
+ sub_v3_v3v3(vecA, ebp->vec, curs);
+ sub_v3_v3v3(vecB, ebp2->vec, curs);
+ distA = len_v3(vecA);
+ distB = len_v3(vecB);
+
+ /* compare distances - closer one therefore acts as direction for bone to go */
+ headtail = (distA < distB) ? 2 : 1;
+ }
+ else if (ebp->head_owner) {
+ headtail = 1;
+ }
+ else if (ebp2->head_owner) {
+ headtail = 2;
+ }
+
+ /* assign head/tail combinations */
+ if (headtail == 2) {
+ copy_v3_v3(head, ebp->vec);
+ copy_v3_v3(tail, ebp2->vec);
+ }
+ else if (headtail == 1) {
+ copy_v3_v3(head, ebp2->vec);
+ copy_v3_v3(tail, ebp->vec);
+ }
+
+ /* add new bone and parent it to the appropriate end */
+ if (headtail) {
+ EditBone *newbone = add_points_bone(obedit, head, tail);
+
+ /* do parenting (will need to set connected flag too) */
+ if (headtail == 2) {
+ /* ebp tail or head - tail gets priority */
+ if (ebp->tail_owner)
+ newbone->parent = ebp->tail_owner;
+ else
+ newbone->parent = ebp->head_owner;
+ }
+ else {
+ /* ebp2 tail or head - tail gets priority */
+ if (ebp2->tail_owner)
+ newbone->parent = ebp2->tail_owner;
+ else
+ newbone->parent = ebp2->head_owner;
+ }
+
+ newbone->flag |= BONE_CONNECTED;
+ }
+ }
+ else {
+ /* FIXME.. figure out a method for multiple bones */
+ BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count);
+ BLI_freelistN(&points);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+
+ /* free points */
+ BLI_freelistN(&points);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_fill(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Fill Between Joints";
+ ot->idname = "ARMATURE_OT_fill";
+ ot->description = "Add bone between selected joint(s) and/or 3D-Cursor";
+
+ /* callbacks */
+ ot->exec = armature_fill_bones_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* --------------------- */
+
+/* this function merges between two bones, removes them and those in-between,
+ * and adjusts the parent relationships for those in-between
+ */
+static void bones_merge(Object *obedit, EditBone *start, EditBone *end, EditBone *endchild, ListBase *chains)
+{
+ bArmature *arm = obedit->data;
+ EditBone *ebo, *ebone, *newbone;
+ LinkData *chain;
+ float head[3], tail[3];
+
+ /* check if same bone */
+ if (start == end) {
+ if (G.debug & G_DEBUG) {
+ printf("Error: same bone!\n");
+ printf("\tstart = %s, end = %s\n", start->name, end->name);
+ }
+ }
+
+ /* step 1: add a new bone
+ * - head = head/tail of start (default head)
+ * - tail = head/tail of end (default tail)
+ * - parent = parent of start
+ */
+ if ((start->flag & BONE_TIPSEL) && (start->flag & BONE_SELECTED) == 0) {
+ copy_v3_v3(head, start->tail);
+ }
+ else {
+ copy_v3_v3(head, start->head);
+ }
+ if ((end->flag & BONE_ROOTSEL) && (end->flag & BONE_SELECTED) == 0) {
+ copy_v3_v3(tail, end->head);
+ }
+ else {
+ copy_v3_v3(tail, end->tail);
+ }
+ newbone = add_points_bone(obedit, head, tail);
+ newbone->parent = start->parent;
+
+ /* TODO, copy more things to the new bone */
+ newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_SCALE |
+ BONE_NO_CYCLICOFFSET | BONE_NO_LOCAL_LOCATION | BONE_DONE);
+
+ /* step 2a: reparent any side chains which may be parented to any bone in the chain of bones to merge
+ * - potentially several tips for side chains leading to some tree exist...
+ */
+ for (chain = chains->first; chain; chain = chain->next) {
+ /* traverse down chain until we hit the bottom or if we run into the tip of the chain of bones we're
+ * merging (need to stop in this case to avoid corrupting this chain too!)
+ */
+ for (ebone = chain->data; (ebone) && (ebone != end); ebone = ebone->parent) {
+ short found = 0;
+
+ /* check if this bone is parented to one in the merging chain
+ * ! WATCHIT: must only go check until end of checking chain
+ */
+ for (ebo = end; (ebo) && (ebo != start->parent); ebo = ebo->parent) {
+ /* side-chain found? --> remap parent to new bone, then we're done with this chain :) */
+ if (ebone->parent == ebo) {
+ ebone->parent = newbone;
+ found = 1;
+ break;
+ }
+ }
+
+ /* carry on to the next tip now */
+ if (found)
+ break;
+ }
+ }
+
+ /* step 2b: parent child of end to newbone (child from this chain) */
+ if (endchild)
+ endchild->parent = newbone;
+
+ /* step 3: delete all bones between and including start and end */
+ for (ebo = end; ebo; ebo = ebone) {
+ ebone = (ebo == start) ? (NULL) : (ebo->parent);
+ bone_free(arm, ebo);
+ }
+
+ newbone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED);
+ ED_armature_sync_selection(arm->edbo);
+}
+
+
+static int armature_merge_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = (obedit) ? obedit->data : NULL;
+ short type = RNA_enum_get(op->ptr, "type");
+
+ /* sanity checks */
+ if (ELEM(NULL, obedit, arm))
+ return OPERATOR_CANCELLED;
+
+ /* for now, there's only really one type of merging that's performed... */
+ if (type == 1) {
+ /* go down chains, merging bones */
+ ListBase chains = {NULL, NULL};
+ LinkData *chain, *nchain;
+ EditBone *ebo;
+
+ armature_tag_select_mirrored(arm);
+
+ /* get chains (ends on chains) */
+ chains_find_tips(arm->edbo, &chains);
+ if (chains.first == NULL) return OPERATOR_CANCELLED;
+
+ /* each 'chain' is the last bone in the chain (with no children) */
+ for (chain = chains.first; chain; chain = nchain) {
+ EditBone *bstart = NULL, *bend = NULL;
+ EditBone *bchild = NULL, *child = NULL;
+
+ /* temporarily remove chain from list of chains */
+ nchain = chain->next;
+ BLI_remlink(&chains, chain);
+
+ /* only consider bones that are visible and selected */
+ for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) {
+ /* check if visible + selected */
+ if (EBONE_VISIBLE(arm, ebo) &&
+ ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) &&
+ (ebo->flag & BONE_SELECTED) )
+ {
+ /* set either end or start (end gets priority, unless it is already set) */
+ if (bend == NULL) {
+ bend = ebo;
+ bchild = child;
+ }
+ else
+ bstart = ebo;
+ }
+ else {
+ /* chain is broken... merge any continous segments then clear */
+ if (bstart && bend)
+ bones_merge(obedit, bstart, bend, bchild, &chains);
+
+ bstart = NULL;
+ bend = NULL;
+ bchild = NULL;
+ }
+ }
+
+ /* merge from bstart to bend if something not merged */
+ if (bstart && bend)
+ bones_merge(obedit, bstart, bend, bchild, &chains);
+
+ /* put back link */
+ BLI_insertlinkbefore(&chains, nchain, chain);
+ }
+
+ armature_tag_unselect(arm);
+
+ BLI_freelistN(&chains);
+ }
+
+ /* updates */
+ ED_armature_sync_selection(arm->edbo);
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_merge(wmOperatorType *ot)
+{
+ static EnumPropertyItem merge_types[] = {
+ {1, "WITHIN_CHAIN", 0, "Within Chains", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Merge Bones";
+ ot->idname = "ARMATURE_OT_merge";
+ ot->description = "Merge continuous chains of selected bones";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_merge_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", merge_types, 0, "Type", "");
+}
+
+/* --------------------- */
+
+/* Switch Direction operator:
+ * Currently, this does not use context loops, as context loops do not make it
+ * easy to retrieve any hierarchical/chain relationships which are necessary for
+ * this to be done easily.
+ */
+
+/* helper to clear BONE_TRANSFORM flags */
+static void armature_clear_swap_done_flags(bArmature *arm)
+{
+ EditBone *ebone;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ ebone->flag &= ~BONE_TRANSFORM;
+ }
+}
+
+static int armature_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm = (bArmature *)ob->data;
+ ListBase chains = {NULL, NULL};
+ LinkData *chain;
+
+ /* get chains of bones (ends on chains) */
+ chains_find_tips(arm->edbo, &chains);
+ if (chains.first == NULL) return OPERATOR_CANCELLED;
+
+ /* ensure that mirror bones will also be operated on */
+ armature_tag_select_mirrored(arm);
+
+ /* clear BONE_TRANSFORM flags
+ * - used to prevent duplicate/cancelling operations from occurring [#34123]
+ * - BONE_DONE cannot be used here as that's already used for mirroring
+ */
+ armature_clear_swap_done_flags(arm);
+
+ /* loop over chains, only considering selected and visible bones */
+ for (chain = chains.first; chain; chain = chain->next) {
+ EditBone *ebo, *child = NULL, *parent = NULL;
+
+ /* loop over bones in chain */
+ for (ebo = chain->data; ebo; ebo = parent) {
+ /* parent is this bone's original parent
+ * - we store this, as the next bone that is checked is this one
+ * but the value of ebo->parent may change here...
+ */
+ parent = ebo->parent;
+
+ /* skip bone if already handled... [#34123] */
+ if ((ebo->flag & BONE_TRANSFORM) == 0) {
+ /* only if selected and editable */
+ if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {
+ /* swap head and tail coordinates */
+ SWAP(float, ebo->head[0], ebo->tail[0]);
+ SWAP(float, ebo->head[1], ebo->tail[1]);
+ SWAP(float, ebo->head[2], ebo->tail[2]);
+
+ /* do parent swapping:
+ * - use 'child' as new parent
+ * - connected flag is only set if points are coincidental
+ */
+ ebo->parent = child;
+ if ((child) && equals_v3v3(ebo->head, child->tail))
+ ebo->flag |= BONE_CONNECTED;
+ else
+ ebo->flag &= ~BONE_CONNECTED;
+
+ /* get next bones
+ * - child will become the new parent of next bone
+ */
+ child = ebo;
+ }
+ else {
+ /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it
+ * as it will be facing in opposite direction
+ */
+ if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) {
+ ebo->parent = NULL;
+ ebo->flag &= ~BONE_CONNECTED;
+ }
+
+ /* get next bones
+ * - child will become new parent of next bone (not swapping occurred,
+ * so set to NULL to prevent infinite-loop)
+ */
+ child = NULL;
+ }
+
+ /* tag as done (to prevent double-swaps) */
+ ebo->flag |= BONE_TRANSFORM;
+ }
+ }
+ }
+
+ /* free chains */
+ BLI_freelistN(&chains);
+
+ /* clear temp flags */
+ armature_clear_swap_done_flags(arm);
+ armature_tag_unselect(arm);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_switch_direction(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Switch Direction";
+ ot->idname = "ARMATURE_OT_switch_direction";
+ ot->description = "Change the direction that a chain of bones points in (head <-> tail swap)";
+
+ /* api callbacks */
+ ot->exec = armature_switch_direction_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************* Align ******************************* */
+
+/* helper to fix a ebone position if its parent has moved due to alignment*/
+static void fix_connected_bone(EditBone *ebone)
+{
+ float diff[3];
+
+ if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) || equals_v3v3(ebone->parent->tail, ebone->head))
+ return;
+
+ /* if the parent has moved we translate child's head and tail accordingly */
+ sub_v3_v3v3(diff, ebone->parent->tail, ebone->head);
+ add_v3_v3(ebone->head, diff);
+ add_v3_v3(ebone->tail, diff);
+}
+
+/* helper to recursively find chains of connected bones starting at ebone and fix their position */
+static void fix_editbone_connected_children(ListBase *edbo, EditBone *ebone)
+{
+ EditBone *selbone;
+
+ for (selbone = edbo->first; selbone; selbone = selbone->next) {
+ if ((selbone->parent) && (selbone->parent == ebone) && (selbone->flag & BONE_CONNECTED)) {
+ fix_connected_bone(selbone);
+ fix_editbone_connected_children(edbo, selbone);
+ }
+ }
+}
+
+static void bone_align_to_bone(ListBase *edbo, EditBone *selbone, EditBone *actbone)
+{
+ float selboneaxis[3], actboneaxis[3], length;
+
+ sub_v3_v3v3(actboneaxis, actbone->tail, actbone->head);
+ normalize_v3(actboneaxis);
+
+ sub_v3_v3v3(selboneaxis, selbone->tail, selbone->head);
+ length = len_v3(selboneaxis);
+
+ mul_v3_fl(actboneaxis, length);
+ add_v3_v3v3(selbone->tail, selbone->head, actboneaxis);
+ selbone->roll = actbone->roll;
+
+ /* if the bone being aligned has connected descendants they must be moved
+ * according to their parent new position, otherwise they would be left
+ * in an inconsistent state: connected but away from the parent*/
+ fix_editbone_connected_children(edbo, selbone);
+}
+
+static int armature_align_bones_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm = (bArmature *)ob->data;
+ EditBone *actbone = CTX_data_active_bone(C);
+ EditBone *actmirb = NULL;
+
+ /* there must be an active bone */
+ if (actbone == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
+ return OPERATOR_CANCELLED;
+ }
+ else if (arm->flag & ARM_MIRROR_EDIT) {
+ /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
+ * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
+ * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
+ * This is useful for arm-chains, for example parenting lower arm to upper arm
+ * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
+ * then just use actbone. Useful when doing upper arm to spine.
+ */
+ actmirb = ED_armature_bone_get_mirrored(arm->edbo, actbone);
+ if (actmirb == NULL)
+ actmirb = actbone;
+ }
+
+ /* if there is only 1 selected bone, we assume that that is the active bone,
+ * since a user will need to have clicked on a bone (thus selecting it) to make it active
+ */
+ if (CTX_DATA_COUNT(C, selected_editable_bones) <= 1) {
+ /* When only the active bone is selected, and it has a parent,
+ * align it to the parent, as that is the only possible outcome.
+ */
+ if (actbone->parent) {
+ bone_align_to_bone(arm->edbo, actbone, actbone->parent);
+
+ if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
+ bone_align_to_bone(arm->edbo, actmirb, actmirb->parent);
+ }
+ }
+ else {
+ /* Align 'selected' bones to the active one
+ * - the context iterator contains both selected bones and their mirrored copies,
+ * so we assume that unselected bones are mirrored copies of some selected bone
+ * - since the active one (and/or its mirror) will also be selected, we also need
+ * to check that we are not trying to operate on them, since such an operation
+ * would cause errors
+ */
+
+ /* align selected bones to the active one */
+ CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
+ {
+ if (ELEM(ebone, actbone, actmirb) == 0) {
+ if (ebone->flag & BONE_SELECTED)
+ bone_align_to_bone(arm->edbo, ebone, actbone);
+ else
+ bone_align_to_bone(arm->edbo, ebone, actmirb);
+ }
+ }
+ CTX_DATA_END;
+ }
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_align(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Align Bones";
+ ot->idname = "ARMATURE_OT_align";
+ ot->description = "Align selected bones to the active bone (or to their parent)";
+
+ /* api callbacks */
+ ot->invoke = WM_operator_confirm;
+ ot->exec = armature_align_bones_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************* Delete ******************************* */
+
+/* previously delete_armature */
+/* only editmode! */
+static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bArmature *arm;
+ EditBone *curBone, *ebone_next;
+ bConstraint *con;
+ Object *obedit = CTX_data_edit_object(C); // XXX get from context
+ arm = obedit->data;
+
+ /* cancel if nothing selected */
+ if (CTX_DATA_COUNT(C, selected_bones) == 0)
+ return OPERATOR_CANCELLED;
+
+ armature_select_mirrored(arm);
+
+ /* First erase any associated pose channel */
+ if (obedit->pose) {
+ bPoseChannel *pchan, *pchan_next;
+ for (pchan = obedit->pose->chanbase.first; pchan; pchan = pchan_next) {
+ pchan_next = pchan->next;
+ curBone = editbone_name_exists(arm->edbo, pchan->name);
+
+ if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
+ BKE_pose_channel_free(pchan);
+ BKE_pose_channels_hash_free(obedit->pose);
+ BLI_freelinkN(&obedit->pose->chanbase, pchan);
+ }
+ else {
+ for (con = pchan->constraints.first; con; con = con->next) {
+ bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if (ct->tar == obedit) {
+ if (ct->subtarget[0]) {
+ curBone = editbone_name_exists(arm->edbo, ct->subtarget);
+ if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
+ con->flag |= CONSTRAINT_DISABLE;
+ ct->subtarget[0] = 0;
+ }
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+ }
+ }
+
+
+ for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
+ ebone_next = curBone->next;
+ if (arm->layer & curBone->layer) {
+ if (curBone->flag & BONE_SELECTED) {
+ if (curBone == arm->act_edbone) arm->act_edbone = NULL;
+ ED_armature_edit_bone_remove(arm, curBone);
+ }
+ }
+ }
+
+
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Selected Bone(s)";
+ ot->idname = "ARMATURE_OT_delete";
+ ot->description = "Remove selected bones from the armature";
+
+ /* api callbacks */
+ ot->invoke = WM_operator_confirm;
+ ot->exec = armature_delete_selected_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************* Show/Hide ******************************* */
+
+static int armature_hide_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *ebone;
+ const int invert = RNA_boolean_get(op->ptr, "unselected") ? BONE_SELECTED : 0;
+
+ /* cancel if nothing selected */
+ if (CTX_DATA_COUNT(C, selected_bones) == 0)
+ return OPERATOR_CANCELLED;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_VISIBLE(arm, ebone)) {
+ if ((ebone->flag & BONE_SELECTED) != invert) {
+ ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ ebone->flag |= BONE_HIDDEN_A;
+ }
+ }
+ }
+ ED_armature_validate_active(arm);
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_hide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Hide Selected Bones";
+ ot->idname = "ARMATURE_OT_hide";
+ ot->description = "Tag selected bones to not be visible in Edit Mode";
+
+ /* api callbacks */
+ ot->exec = armature_hide_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
+}
+
+static int armature_reveal_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *ebone;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (arm->layer & ebone->layer) {
+ if (ebone->flag & BONE_HIDDEN_A) {
+ ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ ebone->flag &= ~BONE_HIDDEN_A;
+ }
+ }
+ }
+ ED_armature_validate_active(arm);
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_reveal(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Reveal Bones";
+ ot->idname = "ARMATURE_OT_reveal";
+ ot->description = "Unhide all bones that have been tagged to be hidden in Edit Mode";
+
+ /* api callbacks */
+ ot->exec = armature_reveal_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+}
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index ddf66a6169b..bfebc68ea46 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -37,17 +37,19 @@ struct wmOperatorType;
struct bContext;
struct Scene;
struct Object;
+struct Base;
struct bAction;
struct bPoseChannel;
struct bArmature;
struct EditBone;
+struct Bone;
struct ListBase;
struct LinkData;
/* ******************************************************* */
-/* editarmature.c operators */
+/* Armature EditMode Operators */
void ARMATURE_OT_bone_primitive_add(struct wmOperatorType *ot);
void ARMATURE_OT_align(struct wmOperatorType *ot);
@@ -131,7 +133,7 @@ void POSE_OT_armature_layers(struct wmOperatorType *ot);
void POSE_OT_bone_layers(struct wmOperatorType *ot);
/* ******************************************************* */
-/* Etch-A-Ton */
+/* Etch-A-Ton (Skeleton Sketching) Operators */
void SKETCH_OT_gesture(struct wmOperatorType *ot);
void SKETCH_OT_delete(struct wmOperatorType *ot);
@@ -144,7 +146,7 @@ void SKETCH_OT_select(struct wmOperatorType *ot);
/* ******************************************************* */
/* Pose Tool Utilities (for PoseLib, Pose Sliding, etc.) */
-/* poseUtils.c */
+/* pose_utils.c */
/* Temporary data linking PoseChannels with the F-Curves they affect */
typedef struct tPChanFCurveLink {
@@ -178,7 +180,7 @@ LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, con
/* ******************************************************* */
/* PoseLib */
-/* poselib.c */
+/* pose_lib.c */
void POSELIB_OT_new(struct wmOperatorType *ot);
void POSELIB_OT_unlink(struct wmOperatorType *ot);
@@ -194,7 +196,7 @@ void POSELIB_OT_apply_pose(struct wmOperatorType *ot);
/* ******************************************************* */
/* Pose Sliding Tools */
-/* poseSlide.c */
+/* pose_slide.c */
void POSE_OT_push(struct wmOperatorType *ot);
void POSE_OT_relax(struct wmOperatorType *ot);
@@ -203,7 +205,11 @@ void POSE_OT_breakdown(struct wmOperatorType *ot);
void POSE_OT_propagate(struct wmOperatorType *ot);
/* ******************************************************* */
-/* editarmature.c */
+/* Various Armature Edit/Pose Editing API's */
+
+/* Ideally, many of these defines would not be needed as everything would be strictly self-contained
+ * within each file, but some tools still have a bit of overlap which makes things messy -- Feb 2013
+ */
EditBone *make_boneList(struct ListBase *edbo, struct ListBase *bones, struct EditBone *parent, struct Bone *actBone);
void BIF_sk_selectStroke(struct bContext *C, const int mval[2], short extend);
@@ -213,13 +219,29 @@ void preEditBoneDuplicate(struct ListBase *editbones);
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);
-/* duplicate method (cross objects */
-
+/* duplicate method (cross objects) */
/* editbones is the target list */
struct EditBone *duplicateEditBoneObjects(struct EditBone *curBone, const char *name, struct ListBase *editbones, struct Object *src_ob, struct Object *dst_ob);
/* editbones is the source list */
void updateDuplicateSubtargetObjects(struct EditBone *dupBone, struct ListBase *editbones, struct Object *src_ob, struct Object *dst_ob);
+
+EditBone *editbone_name_exists(struct ListBase *edbo, const char *name);
+
+EditBone *add_points_bone(struct Object *obedit, float head[3], float tail[3]);
+void bone_free(struct bArmature *arm, struct EditBone *bone);
+
+void armature_tag_select_mirrored(struct bArmature *arm);
+void armature_select_mirrored(struct bArmature *arm);
+void armature_tag_unselect(struct bArmature *arm);
+
+void *get_nearest_bone(struct bContext *C, short findunsel, int x, int y);
+void *get_bone_from_selectbuffer(struct Scene *scene, struct Base *base, unsigned int *buffer, short hits, short findunsel);
+
+int bone_looper(struct Object *ob, struct Bone *bone, void *data,
+ int (*bone_func)(struct Object *, struct Bone *, void *));
+
+
#endif /* __ARMATURE_INTERN_H__ */
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
new file mode 100644
index 00000000000..6417a795712
--- /dev/null
+++ b/source/blender/editors/armature/armature_naming.c
@@ -0,0 +1,368 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators and API's for renaming bones both in and out of Edit Mode
+ */
+
+/** \file blender/editors/armature/armature_naming.c
+ * \ingroup edarmature
+ */
+
+#include <string.h>
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+
+#include "BKE_animsys.h"
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_screen.h"
+
+#include "armature_intern.h"
+
+/* This file contains functions/API's for renaming bones and/or working with them */
+
+/* ************************************************** */
+/* EditBone Names */
+
+/* checks if an EditBone with a matching name already, returning the matching bone if it exists */
+EditBone *editbone_name_exists(ListBase *edbo, const char *name)
+{
+ return BLI_findstring(edbo, name, offsetof(EditBone, name));
+}
+
+/* note: there's a unique_bone_name() too! */
+static int editbone_unique_check(void *arg, const char *name)
+{
+ struct {ListBase *lb; void *bone; } *data = arg;
+ EditBone *dupli = editbone_name_exists(data->lb, name);
+ return dupli && dupli != data->bone;
+}
+
+void unique_editbone_name(ListBase *edbo, char *name, EditBone *bone)
+{
+ struct {ListBase *lb; void *bone; } data;
+ data.lb = edbo;
+ data.bone = bone;
+
+ BLI_uniquename_cb(editbone_unique_check, &data, "Bone", '.', name, sizeof(bone->name));
+}
+
+/* ************************************************** */
+/* Bone Renaming - API */
+
+static int bone_unique_check(void *arg, const char *name)
+{
+ return BKE_armature_find_bone_name((bArmature *)arg, name) != NULL;
+}
+
+static void unique_bone_name(bArmature *arm, char *name)
+{
+ BLI_uniquename_cb(bone_unique_check, (void *)arm, "Bone", '.', name, sizeof(((Bone *)NULL)->name));
+}
+
+/* helper call for armature_bone_rename */
+static void constraint_bone_name_fix(Object *ob, ListBase *conlist, char *oldname, char *newname)
+{
+ bConstraint *curcon;
+ bConstraintTarget *ct;
+
+ for (curcon = conlist->first; curcon; curcon = curcon->next) {
+ bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon);
+ ListBase targets = {NULL, NULL};
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(curcon, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if (ct->tar == ob) {
+ if (!strcmp(ct->subtarget, oldname) )
+ BLI_strncpy(ct->subtarget, newname, MAXBONENAME);
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(curcon, &targets, 0);
+ }
+ }
+}
+
+/* called by UI for renaming a bone */
+/* warning: make sure the original bone was not renamed yet! */
+/* seems messy, but thats what you get with not using pointers but channel names :) */
+void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *newnamep)
+{
+ Object *ob;
+ char newname[MAXBONENAME];
+ char oldname[MAXBONENAME];
+
+ /* names better differ! */
+ if (strncmp(oldnamep, newnamep, MAXBONENAME)) {
+
+ /* we alter newname string... so make copy */
+ BLI_strncpy(newname, newnamep, MAXBONENAME);
+ /* we use oldname for search... so make copy */
+ BLI_strncpy(oldname, oldnamep, MAXBONENAME);
+
+ /* now check if we're in editmode, we need to find the unique name */
+ if (arm->edbo) {
+ EditBone *eBone = editbone_name_exists(arm->edbo, oldname);
+
+ if (eBone) {
+ unique_editbone_name(arm->edbo, newname, NULL);
+ BLI_strncpy(eBone->name, newname, MAXBONENAME);
+ }
+ else return;
+ }
+ else {
+ Bone *bone = BKE_armature_find_bone_name(arm, oldname);
+
+ if (bone) {
+ unique_bone_name(arm, newname);
+ BLI_strncpy(bone->name, newname, MAXBONENAME);
+ }
+ else return;
+ }
+
+ /* do entire dbase - objects */
+ for (ob = G.main->object.first; ob; ob = ob->id.next) {
+ ModifierData *md;
+
+ /* we have the object using the armature */
+ if (arm == ob->data) {
+ Object *cob;
+
+ /* Rename the pose channel, if it exists */
+ if (ob->pose) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, oldname);
+ if (pchan) {
+ BLI_strncpy(pchan->name, newname, MAXBONENAME);
+
+ if (ob->pose->chanhash) {
+ GHash *gh = ob->pose->chanhash;
+
+ /* remove the old hash entry, and replace with the new name */
+ BLI_ghash_remove(gh, oldname, NULL, NULL);
+ BLI_ghash_insert(gh, pchan->name, pchan);
+ }
+ }
+ }
+
+ /* Update any object constraints to use the new bone name */
+ for (cob = G.main->object.first; cob; cob = cob->id.next) {
+ if (cob->constraints.first)
+ constraint_bone_name_fix(ob, &cob->constraints, oldname, newname);
+ if (cob->pose) {
+ bPoseChannel *pchan;
+ for (pchan = cob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ constraint_bone_name_fix(ob, &pchan->constraints, oldname, newname);
+ }
+ }
+ }
+ }
+
+ /* See if an object is parented to this armature */
+ if (ob->parent && (ob->parent->data == arm)) {
+ if (ob->partype == PARBONE) {
+ /* bone name in object */
+ if (!strcmp(ob->parsubstr, oldname))
+ BLI_strncpy(ob->parsubstr, newname, MAXBONENAME);
+ }
+ }
+
+ if (modifiers_usesArmature(ob, arm)) {
+ bDeformGroup *dg = defgroup_find_name(ob, oldname);
+ if (dg) {
+ BLI_strncpy(dg->name, newname, MAXBONENAME);
+ }
+ }
+
+ /* fix modifiers that might be using this name */
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Hook) {
+ HookModifierData *hmd = (HookModifierData *)md;
+
+ /* uses armature, so may use the affected bone name */
+ if (hmd->object && (hmd->object->data == arm)) {
+ if (!strcmp(hmd->subtarget, oldname))
+ BLI_strncpy(hmd->subtarget, newname, MAXBONENAME);
+ }
+ }
+ }
+ }
+
+ /* Fix all animdata that may refer to this bone - we can't just do the ones attached to objects, since
+ * other ID-blocks may have drivers referring to this bone [#29822]
+ */
+ {
+
+ BKE_all_animdata_fix_paths_rename(&arm->id, "pose.bones", oldname, newname);
+ }
+
+ /* correct view locking */
+ {
+ bScreen *screen;
+ for (screen = G.main->screen.first; screen; screen = screen->id.next) {
+ ScrArea *sa;
+ /* add regions */
+ 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) {
+ View3D *v3d = (View3D *)sl;
+ if (v3d->ob_centre && v3d->ob_centre->data == arm) {
+ if (!strcmp(v3d->ob_centre_bone, oldname)) {
+ BLI_strncpy(v3d->ob_centre_bone, newname, MAXBONENAME);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/* ************************************************** */
+/* Bone Renaming - EditMode */
+
+static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm;
+ char newname[MAXBONENAME];
+
+ /* paranoia checks */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+ arm = ob->data;
+
+ /* loop through selected bones, auto-naming them */
+ CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
+ {
+ flip_side_name(newname, ebone->name, TRUE); // 1 = do strip off number extensions
+ ED_armature_bone_rename(arm, ebone->name, newname);
+ }
+ CTX_DATA_END;
+
+ /* since we renamed stuff... */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_flip_names(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Flip Names";
+ ot->idname = "ARMATURE_OT_flip_names";
+ ot->description = "Flips (and corrects) the axis suffixes of the names of selected bones";
+
+ /* api callbacks */
+ ot->exec = armature_flip_names_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int armature_autoside_names_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm;
+ char newname[MAXBONENAME];
+ short axis = RNA_enum_get(op->ptr, "type");
+
+ /* paranoia checks */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+ arm = ob->data;
+
+ /* loop through selected bones, auto-naming them */
+ CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
+ {
+ BLI_strncpy(newname, ebone->name, sizeof(newname));
+ if (bone_autoside_name(newname, 1, axis, ebone->head[axis], ebone->tail[axis]))
+ ED_armature_bone_rename(arm, ebone->name, newname);
+ }
+ CTX_DATA_END;
+
+ /* since we renamed stuff... */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_autoside_names(wmOperatorType *ot)
+{
+ static EnumPropertyItem axis_items[] = {
+ {0, "XAXIS", 0, "X-Axis", "Left/Right"},
+ {1, "YAXIS", 0, "Y-Axis", "Front/Back"},
+ {2, "ZAXIS", 0, "Z-Axis", "Top/Bottom"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "AutoName by Axis";
+ ot->idname = "ARMATURE_OT_autoside_names";
+ ot->description = "Automatically renames the selected bones according to which side of the target axis they fall on";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_autoside_names_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* settings */
+ ot->prop = RNA_def_enum(ot->srna, "type", axis_items, 0, "Axis", "Axis tag names with");
+}
+
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index 7c5b75e56ae..f87d4bc4d47 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -28,15 +28,7 @@
* \ingroup edarmature
*/
-
-#include <stdlib.h>
-#include <math.h>
-
-#include "BLO_sys_types.h"
-
#include "BLI_math.h"
-#include "BLI_blenlib.h"
-
#include "RNA_access.h"
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
new file mode 100644
index 00000000000..c64bb5c4683
--- /dev/null
+++ b/source/blender/editors/armature/armature_relations.c
@@ -0,0 +1,774 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Operators for relations between bones and for transferring bones between armature objects
+ */
+
+/** \file blender/editors/armature/armature_relations.c
+ * \ingroup edarmature
+ */
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BLF_translation.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_object.h"
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "armature_intern.h"
+
+/* *************************************** Join *************************************** */
+/* NOTE: no operator define here as this is exported to the Object-level operator */
+
+/* Helper function for armature joining - link fixing */
+static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone)
+{
+ Object *ob;
+ bPose *pose;
+ bPoseChannel *pchant;
+ bConstraint *con;
+
+ /* let's go through all objects in database */
+ for (ob = G.main->object.first; ob; ob = ob->id.next) {
+ /* do some object-type specific things */
+ if (ob->type == OB_ARMATURE) {
+ pose = ob->pose;
+ for (pchant = pose->chanbase.first; pchant; pchant = pchant->next) {
+ for (con = pchant->constraints.first; con; con = con->next) {
+ bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ /* constraint targets */
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if (ct->tar == srcArm) {
+ if (ct->subtarget[0] == '\0') {
+ ct->tar = tarArm;
+ }
+ else if (strcmp(ct->subtarget, pchan->name) == 0) {
+ ct->tar = tarArm;
+ BLI_strncpy(ct->subtarget, curbone->name, sizeof(ct->subtarget));
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+
+ /* action constraint? */
+ if (con->type == CONSTRAINT_TYPE_ACTION) {
+ bActionConstraint *data = con->data; // XXX old animation system
+ bAction *act;
+ bActionChannel *achan;
+
+ if (data->act) {
+ act = data->act;
+
+ for (achan = act->chanbase.first; achan; achan = achan->next) {
+ if (strcmp(achan->name, pchan->name) == 0)
+ BLI_strncpy(achan->name, curbone->name, sizeof(achan->name));
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ /* fix object-level constraints */
+ if (ob != srcArm) {
+ for (con = ob->constraints.first; con; con = con->next) {
+ bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ /* constraint targets */
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if (ct->tar == srcArm) {
+ if (ct->subtarget[0] == '\0') {
+ ct->tar = tarArm;
+ }
+ else if (strcmp(ct->subtarget, pchan->name) == 0) {
+ ct->tar = tarArm;
+ BLI_strncpy(ct->subtarget, curbone->name, sizeof(ct->subtarget));
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+
+ /* See if an object is parented to this armature */
+ if (ob->parent && (ob->parent == srcArm)) {
+ /* Is object parented to a bone of this src armature? */
+ if (ob->partype == PARBONE) {
+ /* bone name in object */
+ if (!strcmp(ob->parsubstr, pchan->name))
+ BLI_strncpy(ob->parsubstr, curbone->name, sizeof(ob->parsubstr));
+ }
+
+ /* make tar armature be new parent */
+ ob->parent = tarArm;
+ }
+ }
+}
+
+/* join armature exec is exported for use in object->join objects operator... */
+int join_armature_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ bArmature *arm = (ob) ? ob->data : NULL;
+ bPose *pose, *opose;
+ bPoseChannel *pchan, *pchann;
+ EditBone *curbone;
+ float mat[4][4], oimat[4][4];
+
+ /* Ensure we're not in editmode and that the active object is an armature*/
+ if (!ob || ob->type != OB_ARMATURE)
+ return OPERATOR_CANCELLED;
+ if (!arm || arm->edbo)
+ return OPERATOR_CANCELLED;
+
+ /* Get editbones of active armature to add editbones to */
+ ED_armature_to_edit(ob);
+
+ /* get pose of active object and move it out of posemode */
+ pose = ob->pose;
+ ob->mode &= ~OB_MODE_POSE;
+
+ CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases)
+ {
+ if ((base->object->type == OB_ARMATURE) && (base->object != ob)) {
+ bArmature *curarm = base->object->data;
+
+ /* Make a list of editbones in current armature */
+ ED_armature_to_edit(base->object);
+
+ /* Get Pose of current armature */
+ opose = base->object->pose;
+ base->object->mode &= ~OB_MODE_POSE;
+ //BASACT->flag &= ~OB_MODE_POSE;
+
+ /* Find the difference matrix */
+ invert_m4_m4(oimat, ob->obmat);
+ mult_m4_m4m4(mat, oimat, base->object->obmat);
+
+ /* Copy bones and posechannels from the object to the edit armature */
+ for (pchan = opose->chanbase.first; pchan; pchan = pchann) {
+ pchann = pchan->next;
+ curbone = editbone_name_exists(curarm->edbo, pchan->name);
+
+ /* Get new name */
+ unique_editbone_name(arm->edbo, curbone->name, NULL);
+
+ /* Transform the bone */
+ {
+ float premat[4][4];
+ float postmat[4][4];
+ float difmat[4][4];
+ float imat[4][4];
+ float temp[3][3];
+ float delta[3];
+
+ /* Get the premat */
+ sub_v3_v3v3(delta, curbone->tail, curbone->head);
+ vec_roll_to_mat3(delta, curbone->roll, temp);
+
+ unit_m4(premat); /* Mat4MulMat34 only sets 3x3 part */
+ mul_m4_m3m4(premat, temp, mat);
+
+ mul_m4_v3(mat, curbone->head);
+ mul_m4_v3(mat, curbone->tail);
+
+ /* Get the postmat */
+ sub_v3_v3v3(delta, curbone->tail, curbone->head);
+ vec_roll_to_mat3(delta, curbone->roll, temp);
+ copy_m4_m3(postmat, temp);
+
+ /* Find the roll */
+ invert_m4_m4(imat, premat);
+ mult_m4_m4m4(difmat, imat, postmat);
+
+ curbone->roll -= (float)atan2(difmat[2][0], difmat[2][2]);
+ }
+
+ /* Fix Constraints and Other Links to this Bone and Armature */
+ joined_armature_fix_links(ob, base->object, pchan, curbone);
+
+ /* Rename pchan */
+ BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name));
+
+ /* Jump Ship! */
+ BLI_remlink(curarm->edbo, curbone);
+ BLI_addtail(arm->edbo, curbone);
+
+ BLI_remlink(&opose->chanbase, pchan);
+ BLI_addtail(&pose->chanbase, pchan);
+ BKE_pose_channels_hash_free(opose);
+ BKE_pose_channels_hash_free(pose);
+ }
+
+ ED_base_object_free_and_unlink(bmain, scene, base);
+ }
+ }
+ CTX_DATA_END;
+
+ DAG_relations_tag_update(bmain); /* because we removed object(s) */
+
+ ED_armature_from_edit(ob);
+ ED_armature_edit_free(ob);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+/* *********************************** Separate *********************************************** */
+
+/* Helper function for armature separating - link fixing */
+static void separated_armature_fix_links(Object *origArm, Object *newArm)
+{
+ Object *ob;
+ bPoseChannel *pchan;
+ bConstraint *con;
+ ListBase *opchans, *npchans;
+
+ /* get reference to list of bones in original and new armatures */
+ opchans = &origArm->pose->chanbase;
+ npchans = &newArm->pose->chanbase;
+
+ /* let's go through all objects in database */
+ for (ob = G.main->object.first; ob; ob = ob->id.next) {
+ /* do some object-type specific things */
+ if (ob->type == OB_ARMATURE) {
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ for (con = pchan->constraints.first; con; con = con->next) {
+ bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ /* constraint targets */
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ /* any targets which point to original armature are redirected to the new one only if:
+ * - the target isn't origArm/newArm itself
+ * - the target is one that can be found in newArm/origArm
+ */
+ if (ct->subtarget[0] != 0) {
+ if (ct->tar == origArm) {
+ if (BLI_findstring(npchans, ct->subtarget, offsetof(bPoseChannel, name))) {
+ ct->tar = newArm;
+ }
+ }
+ else if (ct->tar == newArm) {
+ if (BLI_findstring(opchans, ct->subtarget, offsetof(bPoseChannel, name))) {
+ ct->tar = origArm;
+ }
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets) {
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+ }
+ }
+
+ /* fix object-level constraints */
+ if (ob != origArm) {
+ for (con = ob->constraints.first; con; con = con->next) {
+ bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ /* constraint targets */
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ /* any targets which point to original armature are redirected to the new one only if:
+ * - the target isn't origArm/newArm itself
+ * - the target is one that can be found in newArm/origArm
+ */
+ if (ct->subtarget[0] != '\0') {
+ if (ct->tar == origArm) {
+ if (BLI_findstring(npchans, ct->subtarget, offsetof(bPoseChannel, name))) {
+ ct->tar = newArm;
+ }
+ }
+ else if (ct->tar == newArm) {
+ if (BLI_findstring(opchans, ct->subtarget, offsetof(bPoseChannel, name))) {
+ ct->tar = origArm;
+ }
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets) {
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+ }
+
+ /* See if an object is parented to this armature */
+ if (ob->parent && (ob->parent == origArm)) {
+ /* Is object parented to a bone of this src armature? */
+ if ((ob->partype == PARBONE) && (ob->parsubstr[0] != '\0')) {
+ if (BLI_findstring(npchans, ob->parsubstr, offsetof(bPoseChannel, name))) {
+ ob->parent = newArm;
+ }
+ }
+ }
+ }
+}
+
+/* Helper function for armature separating - remove certain bones from the given armature
+ * sel: remove selected bones from the armature, otherwise the unselected bones are removed
+ * (ob is not in editmode)
+ */
+static void separate_armature_bones(Object *ob, short sel)
+{
+ bArmature *arm = (bArmature *)ob->data;
+ bPoseChannel *pchan, *pchann;
+ EditBone *curbone;
+
+ /* make local set of editbones to manipulate here */
+ ED_armature_to_edit(ob);
+
+ /* go through pose-channels, checking if a bone should be removed */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchann) {
+ pchann = pchan->next;
+ curbone = editbone_name_exists(arm->edbo, pchan->name);
+
+ /* check if bone needs to be removed */
+ if ( (sel && (curbone->flag & BONE_SELECTED)) ||
+ (!sel && !(curbone->flag & BONE_SELECTED)) )
+ {
+ EditBone *ebo;
+ bPoseChannel *pchn;
+
+ /* clear the bone->parent var of any bone that had this as its parent */
+ for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ if (ebo->parent == curbone) {
+ ebo->parent = NULL;
+ ebo->temp = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */
+ ebo->flag &= ~BONE_CONNECTED;
+ }
+ }
+
+ /* clear the pchan->parent var of any pchan that had this as its parent */
+ for (pchn = ob->pose->chanbase.first; pchn; pchn = pchn->next) {
+ if (pchn->parent == pchan)
+ pchn->parent = NULL;
+ }
+
+ /* free any of the extra-data this pchan might have */
+ BKE_pose_channel_free(pchan);
+ BKE_pose_channels_hash_free(ob->pose);
+
+ /* get rid of unneeded bone */
+ bone_free(arm, curbone);
+ BLI_freelinkN(&ob->pose->chanbase, pchan);
+ }
+ }
+
+ /* exit editmode (recalculates pchans too) */
+ ED_armature_from_edit(ob);
+ ED_armature_edit_free(ob);
+}
+
+/* separate selected bones into their armature */
+static int separate_armature_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ Object *oldob, *newob;
+ Base *oldbase, *newbase;
+
+ /* sanity checks */
+ if (obedit == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* set wait cursor in case this takes a while */
+ WM_cursor_wait(1);
+
+ /* we are going to do this as follows (unlike every other instance of separate):
+ * 1. exit editmode +posemode for active armature/base. Take note of what this is.
+ * 2. duplicate base - BASACT is the new one now
+ * 3. for each of the two armatures, enter editmode -> remove appropriate bones -> exit editmode + recalc
+ * 4. fix constraint links
+ * 5. make original armature active and enter editmode
+ */
+
+ /* 1) only edit-base selected */
+ /* TODO: use context iterators for this? */
+ CTX_DATA_BEGIN(C, Base *, base, visible_bases)
+ {
+ if (base->object == obedit) base->flag |= 1;
+ else base->flag &= ~1;
+ }
+ CTX_DATA_END;
+
+ /* 1) store starting settings and exit editmode */
+ oldob = obedit;
+ oldbase = BASACT;
+ oldob->mode &= ~OB_MODE_POSE;
+ //oldbase->flag &= ~OB_POSEMODE;
+
+ ED_armature_from_edit(obedit);
+ ED_armature_edit_free(obedit);
+
+ /* 2) duplicate base */
+ newbase = ED_object_add_duplicate(bmain, scene, oldbase, USER_DUP_ARM); /* only duplicate linked armature */
+ DAG_relations_tag_update(bmain);
+
+ newob = newbase->object;
+ newbase->flag &= ~SELECT;
+
+
+ /* 3) remove bones that shouldn't still be around on both armatures */
+ separate_armature_bones(oldob, 1);
+ separate_armature_bones(newob, 0);
+
+
+ /* 4) fix links before depsgraph flushes */ // err... or after?
+ separated_armature_fix_links(oldob, newob);
+
+ DAG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* this is the original one */
+ DAG_id_tag_update(&newob->id, OB_RECALC_DATA); /* this is the separated one */
+
+
+ /* 5) restore original conditions */
+ obedit = oldob;
+
+ ED_armature_to_edit(obedit);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
+
+ /* recalc/redraw + cleanup */
+ WM_cursor_wait(0);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_separate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Separate Bones";
+ ot->idname = "ARMATURE_OT_separate";
+ ot->description = "Isolate selected bones into a separate armature";
+
+ /* callbacks */
+ ot->invoke = WM_operator_confirm;
+ ot->exec = separate_armature_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ******************************************** Parenting ************************************************* */
+
+/* armature parenting options */
+#define ARM_PAR_CONNECT 1
+#define ARM_PAR_OFFSET 2
+
+
+/* check for null, before calling! */
+static void bone_connect_to_existing_parent(EditBone *bone)
+{
+ bone->flag |= BONE_CONNECTED;
+ copy_v3_v3(bone->head, bone->parent->tail);
+ bone->rad_head = bone->parent->rad_tail;
+}
+
+static void bone_connect_to_new_parent(ListBase *edbo, EditBone *selbone, EditBone *actbone, short mode)
+{
+ EditBone *ebone;
+ float offset[3];
+
+ if ((selbone->parent) && (selbone->flag & BONE_CONNECTED))
+ selbone->parent->flag &= ~(BONE_TIPSEL);
+
+ /* make actbone the parent of selbone */
+ selbone->parent = actbone;
+
+ /* in actbone tree we cannot have a loop */
+ for (ebone = actbone->parent; ebone; ebone = ebone->parent) {
+ if (ebone->parent == selbone) {
+ ebone->parent = NULL;
+ ebone->flag &= ~BONE_CONNECTED;
+ }
+ }
+
+ if (mode == ARM_PAR_CONNECT) {
+ /* Connected: Child bones will be moved to the parent tip */
+ selbone->flag |= BONE_CONNECTED;
+ sub_v3_v3v3(offset, actbone->tail, selbone->head);
+
+ copy_v3_v3(selbone->head, actbone->tail);
+ selbone->rad_head = actbone->rad_tail;
+
+ add_v3_v3(selbone->tail, offset);
+
+ /* offset for all its children */
+ for (ebone = edbo->first; ebone; ebone = ebone->next) {
+ EditBone *par;
+
+ for (par = ebone->parent; par; par = par->parent) {
+ if (par == selbone) {
+ add_v3_v3(ebone->head, offset);
+ add_v3_v3(ebone->tail, offset);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ /* Offset: Child bones will retain their distance from the parent tip */
+ selbone->flag &= ~BONE_CONNECTED;
+ }
+}
+
+
+static EnumPropertyItem prop_editarm_make_parent_types[] = {
+ {ARM_PAR_CONNECT, "CONNECTED", 0, "Connected", ""},
+ {ARM_PAR_OFFSET, "OFFSET", 0, "Keep Offset", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int armature_parent_set_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm = (bArmature *)ob->data;
+ EditBone *actbone = CTX_data_active_bone(C);
+ EditBone *actmirb = NULL;
+ short val = RNA_enum_get(op->ptr, "type");
+
+ /* there must be an active bone */
+ if (actbone == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
+ return OPERATOR_CANCELLED;
+ }
+ else if (arm->flag & ARM_MIRROR_EDIT) {
+ /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
+ * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
+ * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
+ * This is useful for arm-chains, for example parenting lower arm to upper arm
+ * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
+ * then just use actbone. Useful when doing upper arm to spine.
+ */
+ actmirb = ED_armature_bone_get_mirrored(arm->edbo, actbone);
+ if (actmirb == NULL)
+ actmirb = actbone;
+ }
+
+ /* if there is only 1 selected bone, we assume that that is the active bone,
+ * since a user will need to have clicked on a bone (thus selecting it) to make it active
+ */
+ if (CTX_DATA_COUNT(C, selected_editable_bones) <= 1) {
+ /* When only the active bone is selected, and it has a parent,
+ * connect it to the parent, as that is the only possible outcome.
+ */
+ if (actbone->parent) {
+ bone_connect_to_existing_parent(actbone);
+
+ if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
+ bone_connect_to_existing_parent(actmirb);
+ }
+ }
+ else {
+ /* Parent 'selected' bones to the active one
+ * - the context iterator contains both selected bones and their mirrored copies,
+ * so we assume that unselected bones are mirrored copies of some selected bone
+ * - since the active one (and/or its mirror) will also be selected, we also need
+ * to check that we are not trying to operate on them, since such an operation
+ * would cause errors
+ */
+
+ /* parent selected bones to the active one */
+ CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
+ {
+ if (ELEM(ebone, actbone, actmirb) == 0) {
+ if (ebone->flag & BONE_SELECTED)
+ bone_connect_to_new_parent(arm->edbo, ebone, actbone, val);
+ else
+ bone_connect_to_new_parent(arm->edbo, ebone, actmirb, val);
+ }
+ }
+ CTX_DATA_END;
+ }
+
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
+{
+ EditBone *actbone = CTX_data_active_bone(C);
+ uiPopupMenu *pup = uiPupMenuBegin(C, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Make Parent"), ICON_NONE);
+ uiLayout *layout = uiPupMenuLayout(pup);
+ int allchildbones = 0;
+
+ CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
+ {
+ if (ebone != actbone) {
+ if (ebone->parent != actbone) allchildbones = 1;
+ }
+ }
+ CTX_DATA_END;
+
+ uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT);
+
+ /* ob becomes parent, make the associated menus */
+ if (allchildbones)
+ uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET);
+
+ uiPupMenuEnd(C, pup);
+
+ return OPERATOR_CANCELLED;
+}
+
+void ARMATURE_OT_parent_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Make Parent";
+ ot->idname = "ARMATURE_OT_parent_set";
+ ot->description = "Set the active bone as the parent of the selected bones";
+
+ /* api callbacks */
+ ot->invoke = armature_parent_set_invoke;
+ ot->exec = armature_parent_set_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "type", prop_editarm_make_parent_types, 0, "ParentType", "Type of parenting");
+}
+
+
+
+static EnumPropertyItem prop_editarm_clear_parent_types[] = {
+ {1, "CLEAR", 0, "Clear Parent", ""},
+ {2, "DISCONNECT", 0, "Disconnect Bone", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static void editbone_clear_parent(EditBone *ebone, int mode)
+{
+ if (ebone->parent) {
+ /* for nice selection */
+ ebone->parent->flag &= ~(BONE_TIPSEL);
+ }
+
+ if (mode == 1) ebone->parent = NULL;
+ ebone->flag &= ~BONE_CONNECTED;
+}
+
+static int armature_parent_clear_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm = (bArmature *)ob->data;
+ int val = RNA_enum_get(op->ptr, "type");
+
+ CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
+ {
+ editbone_clear_parent(ebone, val);
+ }
+ CTX_DATA_END;
+
+ ED_armature_sync_selection(arm->edbo);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_parent_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Parent";
+ ot->idname = "ARMATURE_OT_parent_clear";
+ ot->description = "Remove the parent-child relationship between selected bones and their parents";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_parent_clear_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_editarm_clear_parent_types, 0, "ClearType", "What way to clear parenting");
+}
+
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
new file mode 100644
index 00000000000..b7a436cc209
--- /dev/null
+++ b/source/blender/editors/armature/armature_select.c
@@ -0,0 +1,940 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * API's and Operators for selecting armature bones in EditMode
+ */
+
+/** \file blender/editors/armature/armature_select.c
+ * \ingroup edarmature
+ */
+
+#include "DNA_armature_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_report.h"
+
+#include "BIF_gl.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "armature_intern.h"
+
+/* **************** PoseMode & EditMode Selection Buffer Queries *************************** */
+
+/* only for opengl selection indices */
+Bone *get_indexed_bone(Object *ob, int index)
+{
+ bPoseChannel *pchan;
+ if (ob->pose == NULL) return NULL;
+ index >>= 16; // bone selection codes use left 2 bytes
+
+ pchan = BLI_findlink(&ob->pose->chanbase, index);
+ return pchan ? pchan->bone : NULL;
+}
+
+/* See if there are any selected bones in this buffer */
+/* only bones from base are checked on */
+void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits, short findunsel)
+{
+ Object *obedit = scene->obedit; // XXX get from context
+ Bone *bone;
+ EditBone *ebone;
+ void *firstunSel = NULL, *firstSel = NULL, *data;
+ unsigned int hitresult;
+ short i, takeNext = 0, sel;
+
+ for (i = 0; i < hits; i++) {
+ hitresult = buffer[3 + (i * 4)];
+
+ if (!(hitresult & BONESEL_NOSEL)) { // -1
+ if (hitresult & BONESEL_ANY) { // to avoid including objects in selection
+
+ hitresult &= ~(BONESEL_ANY);
+ /* Determine what the current bone is */
+ if (obedit == NULL || base->object != obedit) {
+ /* no singular posemode, so check for correct object */
+ if (base->selcol == (hitresult & 0xFFFF)) {
+ bone = get_indexed_bone(base->object, hitresult);
+
+ if (findunsel)
+ sel = (bone->flag & BONE_SELECTED);
+ else
+ sel = !(bone->flag & BONE_SELECTED);
+
+ data = bone;
+ }
+ else {
+ data = NULL;
+ sel = 0;
+ }
+ }
+ else {
+ bArmature *arm = obedit->data;
+
+ ebone = BLI_findlink(arm->edbo, hitresult);
+ if (findunsel)
+ sel = (ebone->flag & BONE_SELECTED);
+ else
+ sel = !(ebone->flag & BONE_SELECTED);
+
+ data = ebone;
+ }
+
+ if (data) {
+ if (sel) {
+ if (!firstSel) firstSel = data;
+ takeNext = 1;
+ }
+ else {
+ if (!firstunSel)
+ firstunSel = data;
+ if (takeNext)
+ return data;
+ }
+ }
+ }
+ }
+ }
+
+ if (firstunSel)
+ return firstunSel;
+ else
+ return firstSel;
+}
+
+/* used by posemode as well editmode */
+/* only checks scene->basact! */
+/* x and y are mouse coords (area space) */
+void *get_nearest_bone(bContext *C, short findunsel, int x, int y)
+{
+ ViewContext vc;
+ rcti rect;
+ unsigned int buffer[MAXPICKBUF];
+ short hits;
+
+ view3d_set_viewcontext(C, &vc);
+
+ // rect.xmin = ... mouseco!
+ rect.xmin = rect.xmax = x;
+ rect.ymin = rect.ymax = y;
+
+ glInitNames();
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
+
+ if (hits > 0)
+ return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel);
+
+ return NULL;
+}
+
+/* **************** EditMode stuff ********************** */
+
+/* called in space.c */
+/* previously "selectconnected_armature" */
+static int armature_select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ bArmature *arm;
+ EditBone *bone, *curBone, *next;
+ int extend = RNA_boolean_get(op->ptr, "extend");
+ Object *obedit = CTX_data_edit_object(C);
+ arm = obedit->data;
+
+ view3d_operator_needs_opengl(C);
+
+ if (extend)
+ bone = get_nearest_bone(C, 0, event->mval[0], event->mval[1]);
+ else
+ bone = get_nearest_bone(C, 1, event->mval[0], event->mval[1]);
+
+ if (!bone)
+ return OPERATOR_CANCELLED;
+
+ /* Select parents */
+ for (curBone = bone; curBone; curBone = next) {
+ if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
+ if (extend) {
+ curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+
+ if (curBone->flag & BONE_CONNECTED)
+ next = curBone->parent;
+ else
+ next = NULL;
+ }
+
+ /* Select children */
+ while (bone) {
+ for (curBone = arm->edbo->first; curBone; curBone = next) {
+ next = curBone->next;
+ if ((curBone->parent == bone) && (curBone->flag & BONE_UNSELECTABLE) == 0) {
+ if (curBone->flag & BONE_CONNECTED) {
+ if (extend)
+ curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ else
+ curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ bone = curBone;
+ break;
+ }
+ else {
+ bone = NULL;
+ break;
+ }
+ }
+ }
+ if (!curBone)
+ bone = NULL;
+ }
+
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+static int armature_select_linked_poll(bContext *C)
+{
+ return (ED_operator_view3d_active(C) && ED_operator_editarmature(C) );
+}
+
+void ARMATURE_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Connected";
+ ot->idname = "ARMATURE_OT_select_linked";
+ ot->description = "Select bones related to selected ones by parent/child relationships";
+
+ /* api callbacks */
+ ot->exec = NULL;
+ ot->invoke = armature_select_linked_invoke;
+ ot->poll = armature_select_linked_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
+}
+
+/* does bones and points */
+/* note that BONE ROOT only gets drawn for root bones (or without IK) */
+static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
+ ListBase *edbo, int findunsel, int *selmask)
+{
+ bArmature *arm = (bArmature *)vc->obedit->data;
+ EditBone *ebone_next_act = arm->act_edbone;
+
+ EditBone *ebone;
+ rcti rect;
+ unsigned int buffer[MAXPICKBUF];
+ unsigned int hitresult, besthitresult = BONESEL_NOSEL;
+ int i, mindep = 4;
+ short hits;
+
+ glInitNames();
+
+ /* find the bone after the current active bone, so as to bump up its chances in selection.
+ * this way overlapping bones will cycle selection state as with objects. */
+ if (ebone_next_act &&
+ EBONE_VISIBLE(arm, ebone_next_act) &&
+ ebone_next_act->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL))
+ {
+ ebone_next_act = ebone_next_act->next ? ebone_next_act->next : arm->edbo->first;
+ }
+ else {
+ ebone_next_act = NULL;
+ }
+
+ rect.xmin = mval[0] - 5;
+ rect.xmax = mval[0] + 5;
+ rect.ymin = mval[1] - 5;
+ rect.ymax = mval[1] + 5;
+
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
+ if (hits == 0) {
+ rect.xmin = mval[0] - 12;
+ rect.xmax = mval[0] + 12;
+ rect.ymin = mval[1] - 12;
+ rect.ymax = mval[1] + 12;
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
+ }
+ /* See if there are any selected bones in this group */
+ if (hits > 0) {
+
+ if (hits == 1) {
+ if (!(buffer[3] & BONESEL_NOSEL))
+ besthitresult = buffer[3];
+ }
+ else {
+ for (i = 0; i < hits; i++) {
+ hitresult = buffer[3 + (i * 4)];
+ if (!(hitresult & BONESEL_NOSEL)) {
+ int dep;
+
+ ebone = BLI_findlink(edbo, hitresult & ~BONESEL_ANY);
+
+ /* clicks on bone points get advantage */
+ if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
+ /* but also the unselected one */
+ if (findunsel) {
+ if ( (hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0)
+ dep = 1;
+ else if ( (hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0)
+ dep = 1;
+ else
+ dep = 2;
+ }
+ else dep = 2;
+ }
+ else {
+ /* bone found */
+ if (findunsel) {
+ if ((ebone->flag & BONE_SELECTED) == 0)
+ dep = 2;
+ else
+ dep = 3;
+ }
+ else dep = 3;
+ }
+
+ if (ebone == ebone_next_act) {
+ dep -= 1;
+ }
+
+ if (dep < mindep) {
+ mindep = dep;
+ besthitresult = hitresult;
+ }
+ }
+ }
+ }
+
+ if (!(besthitresult & BONESEL_NOSEL)) {
+
+ ebone = BLI_findlink(edbo, besthitresult & ~BONESEL_ANY);
+
+ *selmask = 0;
+ if (besthitresult & BONESEL_ROOT)
+ *selmask |= BONE_ROOTSEL;
+ if (besthitresult & BONESEL_TIP)
+ *selmask |= BONE_TIPSEL;
+ if (besthitresult & BONESEL_BONE)
+ *selmask |= BONE_SELECTED;
+ return ebone;
+ }
+ }
+ *selmask = 0;
+ return NULL;
+}
+
+
+
+/* toggle==0: deselect
+ * toggle==1: swap (based on test)
+ * toggle==2: swap (no test), CURRENTLY UNUSED
+ */
+void ED_armature_deselect_all(Object *obedit, int toggle)
+{
+ bArmature *arm = obedit->data;
+ EditBone *eBone;
+ int sel = 1;
+
+ if (toggle == 1) {
+ /* Determine if there are any selected bones
+ * and therefore whether we are selecting or deselecting */
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ // if (arm->layer & eBone->layer) {
+ if (eBone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
+ sel = 0;
+ break;
+ }
+ // }
+ }
+ }
+ else sel = toggle;
+
+ /* Set the flags */
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ if (sel == 2) {
+ /* invert selection of bone */
+ if (EBONE_VISIBLE(arm, eBone)) {
+ eBone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ if (arm->act_edbone == eBone)
+ arm->act_edbone = NULL;
+ }
+ }
+ else if (sel == 1) {
+ /* select bone */
+ if (EBONE_VISIBLE(arm, eBone)) {
+ eBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ if (eBone->parent)
+ eBone->parent->flag |= (BONE_TIPSEL);
+ }
+ }
+ else {
+ /* deselect bone */
+ eBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ if (arm->act_edbone == eBone)
+ arm->act_edbone = NULL;
+ }
+ }
+
+ ED_armature_sync_selection(arm->edbo);
+}
+
+void ED_armature_deselect_all_visible(Object *obedit)
+{
+ bArmature *arm = obedit->data;
+ EditBone *ebone;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ /* first and foremost, bone must be visible and selected */
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+
+ ED_armature_sync_selection(arm->edbo);
+}
+
+/* accounts for connected parents */
+static int ebone_select_flag(EditBone *ebone)
+{
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ return ((ebone->parent->flag & BONE_TIPSEL) ? BONE_ROOTSEL : 0) | (ebone->flag & (BONE_SELECTED | BONE_TIPSEL));
+ }
+ else {
+ return ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+ }
+}
+
+/* context: editmode armature in view3d */
+int mouse_armature(bContext *C, const int mval[2], int extend, int deselect, int toggle)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ ViewContext vc;
+ EditBone *nearBone = NULL;
+ int selmask;
+
+ view3d_set_viewcontext(C, &vc);
+
+ BIF_sk_selectStroke(C, mval, extend);
+
+ nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, 1, &selmask);
+ if (nearBone) {
+
+ if (!extend && !deselect && !toggle)
+ ED_armature_deselect_all(obedit, 0);
+
+ /* by definition the non-root connected bones have no root point drawn,
+ * so a root selection needs to be delivered to the parent tip */
+
+ if (selmask & BONE_SELECTED) {
+ if (nearBone->parent && (nearBone->flag & BONE_CONNECTED)) {
+ /* click in a chain */
+ if (extend) {
+ /* select this bone */
+ nearBone->flag |= BONE_TIPSEL;
+ nearBone->parent->flag |= BONE_TIPSEL;
+ }
+ else if (deselect) {
+ /* deselect this bone */
+ nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
+ /* only deselect parent tip if it is not selected */
+ if (!(nearBone->parent->flag & BONE_SELECTED))
+ nearBone->parent->flag &= ~BONE_TIPSEL;
+ }
+ else if (toggle) {
+ /* hold shift inverts this bone's selection */
+ if (nearBone->flag & BONE_SELECTED) {
+ /* deselect this bone */
+ nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
+ /* only deselect parent tip if it is not selected */
+ if (!(nearBone->parent->flag & BONE_SELECTED))
+ nearBone->parent->flag &= ~BONE_TIPSEL;
+ }
+ else {
+ /* select this bone */
+ nearBone->flag |= BONE_TIPSEL;
+ nearBone->parent->flag |= BONE_TIPSEL;
+ }
+ }
+ else {
+ /* select this bone */
+ nearBone->flag |= BONE_TIPSEL;
+ nearBone->parent->flag |= BONE_TIPSEL;
+ }
+ }
+ else {
+ if (extend) {
+ nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else if (deselect) {
+ nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else if (toggle) {
+ /* hold shift inverts this bone's selection */
+ if (nearBone->flag & BONE_SELECTED)
+ nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
+ else
+ nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else
+ nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+ else {
+ if (extend)
+ nearBone->flag |= selmask;
+ else if (deselect)
+ nearBone->flag &= ~selmask;
+ else if (toggle && (nearBone->flag & selmask))
+ nearBone->flag &= ~selmask;
+ else
+ nearBone->flag |= selmask;
+ }
+
+ ED_armature_sync_selection(arm->edbo);
+
+ if (nearBone) {
+ /* then now check for active status */
+ if (ebone_select_flag(nearBone)) {
+ arm->act_edbone = nearBone;
+ }
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* **************** Selections ******************/
+
+static int armature_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ /* Set the flags */
+ CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
+ {
+ /* ignore bone if selection can't change */
+ if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
+ /* select bone */
+ ebone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+ CTX_DATA_END;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_select_inverse(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Inverse";
+ ot->idname = "ARMATURE_OT_select_inverse";
+ ot->description = "Flip the selection status of bones (selected -> unselected, unselected -> selected)";
+
+ /* api callbacks */
+ ot->exec = armature_select_inverse_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+}
+static int armature_de_select_all_exec(bContext *C, wmOperator *op)
+{
+ int action = RNA_enum_get(op->ptr, "action");
+
+ if (action == SEL_TOGGLE) {
+ action = SEL_SELECT;
+ /* Determine if there are any selected bones
+ * And therefore whether we are selecting or deselecting */
+ if (CTX_DATA_COUNT(C, selected_bones) > 0)
+ action = SEL_DESELECT;
+ }
+
+ /* Set the flags */
+ CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
+ {
+ /* ignore bone if selection can't change */
+ if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
+ switch (action) {
+ case SEL_SELECT:
+ ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ if (ebone->parent)
+ ebone->parent->flag |= (BONE_TIPSEL);
+ break;
+ case SEL_DESELECT:
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ break;
+ case SEL_INVERT:
+ if (ebone->flag & BONE_SELECTED) {
+ ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ if (ebone->parent)
+ ebone->parent->flag |= (BONE_TIPSEL);
+ }
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_select_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "(De)select All";
+ ot->idname = "ARMATURE_OT_select_all";
+ ot->description = "Toggle selection status of all bones";
+
+ /* api callbacks */
+ ot->exec = armature_de_select_all_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ WM_operator_properties_select_all(ot);
+}
+
+enum {
+ SIMEDBONE_LENGTH = 1,
+ SIMEDBONE_DIRECTION,
+ SIMEDBONE_PREFIX,
+ SIMEDBONE_SUFFIX,
+ SIMEDBONE_LAYER
+};
+
+static EnumPropertyItem prop_similar_types[] = {
+ {SIMEDBONE_LENGTH, "LENGTH", 0, "Length", ""},
+ {SIMEDBONE_DIRECTION, "DIRECTION", 0, "Direction (Y axis)", ""},
+ {SIMEDBONE_PREFIX, "PREFIX", 0, "Prefix", ""},
+ {SIMEDBONE_SUFFIX, "SUFFIX", 0, "Suffix", ""},
+ {SIMEDBONE_LAYER, "LAYER", 0, "Layer", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+/* could be used in more places */
+static void ED_armature_edit_bone_select(EditBone *ebone)
+{
+ BLI_assert((ebone->flag & BONE_UNSELECTABLE) == 0);
+ ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+
+ if ((ebone->flag & BONE_CONNECTED) && (ebone->parent != NULL)) {
+ ebone->parent->flag |= BONE_TIPSEL;
+ }
+}
+
+static void select_similar_length(bArmature *arm, EditBone *ebone_act, const float thresh)
+{
+ EditBone *ebone;
+
+ /* thresh is always relative to current length */
+ const float len_min = ebone_act->length / (1.0f + thresh);
+ const float len_max = ebone_act->length * (1.0f + thresh);
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ if ((ebone->length >= len_min) &&
+ (ebone->length <= len_max))
+ {
+ ED_armature_edit_bone_select(ebone);
+ }
+ }
+ }
+}
+
+static void select_similar_direction(bArmature *arm, EditBone *ebone_act, const float thresh)
+{
+ EditBone *ebone;
+ float dir_act[3];
+ sub_v3_v3v3(dir_act, ebone_act->head, ebone_act->tail);
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ float dir[3];
+ sub_v3_v3v3(dir, ebone->head, ebone->tail);
+
+ if (angle_v3v3(dir_act, dir) / (float)M_PI < thresh) {
+ ED_armature_edit_bone_select(ebone);
+ }
+ }
+ }
+}
+
+static void select_similar_layer(bArmature *arm, EditBone *ebone_act)
+{
+ EditBone *ebone;
+
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ if (ebone->layer & ebone_act->layer) {
+ ED_armature_edit_bone_select(ebone);
+ }
+ }
+ }
+}
+
+static void select_similar_prefix(bArmature *arm, EditBone *ebone_act)
+{
+ EditBone *ebone;
+
+ char body_tmp[MAX_VGROUP_NAME];
+ char prefix_act[MAX_VGROUP_NAME];
+
+ BKE_deform_split_prefix(ebone_act->name, prefix_act, body_tmp);
+
+ if (prefix_act[0] == '\0')
+ return;
+
+ /* Find matches */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ char prefix_other[MAX_VGROUP_NAME];
+ BKE_deform_split_prefix(ebone->name, prefix_other, body_tmp);
+ if (!strcmp(prefix_act, prefix_other)) {
+ ED_armature_edit_bone_select(ebone);
+ }
+ }
+ }
+}
+
+static void select_similar_suffix(bArmature *arm, EditBone *ebone_act)
+{
+ EditBone *ebone;
+
+ char body_tmp[MAX_VGROUP_NAME];
+ char suffix_act[MAX_VGROUP_NAME];
+
+ BKE_deform_split_suffix(ebone_act->name, body_tmp, suffix_act);
+
+ if (suffix_act[0] == '\0')
+ return;
+
+ /* Find matches */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ char suffix_other[MAX_VGROUP_NAME];
+ BKE_deform_split_suffix(ebone->name, body_tmp, suffix_other);
+ if (!strcmp(suffix_act, suffix_other)) {
+ ED_armature_edit_bone_select(ebone);
+ }
+ }
+ }
+}
+
+static int armature_select_similar_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ bArmature *arm = obedit->data;
+ EditBone *ebone_act = CTX_data_active_bone(C);
+
+ /* Get props */
+ int type = RNA_enum_get(op->ptr, "type");
+ float thresh = RNA_float_get(op->ptr, "threshold");
+
+ /* Check for active bone */
+ if (ebone_act == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
+ return OPERATOR_CANCELLED;
+ }
+
+ switch (type) {
+ case SIMEDBONE_LENGTH:
+ select_similar_length(arm, ebone_act, thresh);
+ break;
+ case SIMEDBONE_DIRECTION:
+ select_similar_direction(arm, ebone_act, thresh);
+ break;
+ case SIMEDBONE_PREFIX:
+ select_similar_prefix(arm, ebone_act);
+ break;
+ case SIMEDBONE_SUFFIX:
+ select_similar_suffix(arm, ebone_act);
+ break;
+ case SIMEDBONE_LAYER:
+ select_similar_layer(arm, ebone_act);
+ break;
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_select_similar(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Similar";
+ ot->idname = "ARMATURE_OT_select_similar";
+
+ /* callback functions */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = armature_select_similar_exec;
+ ot->poll = ED_operator_editarmature;
+ ot->description = "Select similar bones by property types";
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, 0, "Type", "");
+ RNA_def_float(ot->srna, "threshold", 0.1f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
+}
+
+/* ********************* select hierarchy operator ************** */
+
+/* Get the first available child of an editbone */
+static EditBone *editbone_get_child(bArmature *arm, EditBone *pabone, short use_visibility)
+{
+ EditBone *curbone, *chbone = NULL;
+
+ for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
+ if (curbone->parent == pabone) {
+ if (use_visibility) {
+ if ((arm->layer & curbone->layer) && !(pabone->flag & BONE_HIDDEN_A)) {
+ chbone = curbone;
+ }
+ }
+ else
+ chbone = curbone;
+ }
+ }
+
+ return chbone;
+}
+
+static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Object *ob;
+ bArmature *arm;
+ EditBone *curbone, *pabone, *chbone;
+ int direction = RNA_enum_get(op->ptr, "direction");
+ int add_to_sel = RNA_boolean_get(op->ptr, "extend");
+
+ ob = obedit;
+ arm = (bArmature *)ob->data;
+
+ for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
+ /* only work on bone if it is visible and its selection can change */
+ if (EBONE_SELECTABLE(arm, curbone)) {
+ if (curbone == arm->act_edbone) {
+ if (direction == BONE_SELECT_PARENT) {
+ if (curbone->parent == NULL) continue;
+ else pabone = curbone->parent;
+
+ if (EBONE_VISIBLE(arm, pabone)) {
+ pabone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_edbone = pabone;
+ if (pabone->parent) pabone->parent->flag |= BONE_TIPSEL;
+
+ if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ break;
+ }
+
+ }
+ else { // BONE_SELECT_CHILD
+ chbone = editbone_get_child(arm, curbone, 1);
+ if (chbone == NULL) continue;
+
+ if (EBONE_SELECTABLE(arm, chbone)) {
+ chbone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_edbone = chbone;
+
+ if (!add_to_sel) {
+ curbone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL);
+ if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ ED_armature_sync_selection(arm->edbo);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_select_hierarchy(wmOperatorType *ot)
+{
+ static EnumPropertyItem direction_items[] = {
+ {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
+ {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Select Hierarchy";
+ ot->idname = "ARMATURE_OT_select_hierarchy";
+ ot->description = "Select immediate parent/children of selected bones";
+
+ /* api callbacks */
+ ot->exec = armature_select_hierarchy_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "direction", direction_items,
+ BONE_SELECT_PARENT, "Direction", "");
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
+}
+
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
new file mode 100644
index 00000000000..2e43c388fa8
--- /dev/null
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -0,0 +1,441 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * API's for creating vertex groups from bones
+ * - Interfaces with heat weighting in meshlaplacian
+ */
+
+/** \file blender/editors/armature/armature_skinning.c
+ * \ingroup edarmature
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_deform.h"
+#include "BKE_report.h"
+#include "BKE_subsurf.h"
+#include "BKE_modifier.h"
+
+#include "ED_armature.h"
+#include "ED_mesh.h"
+
+
+#include "armature_intern.h"
+#include "meshlaplacian.h"
+
+#if 0
+#include "reeb.h"
+#endif
+
+/* ********************************** Bone Skinning *********************************************** */
+
+static int bone_skinnable_cb(Object *ob, Bone *bone, void *datap)
+{
+ /* Bones that are deforming
+ * are regarded to be "skinnable" and are eligible for
+ * auto-skinning.
+ *
+ * This function performs 2 functions:
+ *
+ * a) It returns 1 if the bone is skinnable.
+ * If we loop over all bones with this
+ * function, we can count the number of
+ * skinnable bones.
+ * b) If the pointer data is non null,
+ * it is treated like a handle to a
+ * bone pointer -- the bone pointer
+ * is set to point at this bone, and
+ * the pointer the handle points to
+ * is incremented to point to the
+ * next member of an array of pointers
+ * to bones. This way we can loop using
+ * this function to construct an array of
+ * pointers to bones that point to all
+ * skinnable bones.
+ */
+ Bone ***hbone;
+ int a, segments;
+ struct { Object *armob; void *list; int heat; } *data = datap;
+
+ if (!(ob->mode & OB_MODE_WEIGHT_PAINT) || !(bone->flag & BONE_HIDDEN_P)) {
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name))
+ segments = bone->segments;
+ else
+ segments = 1;
+
+ if (data->list != NULL) {
+ hbone = (Bone ***) &data->list;
+
+ for (a = 0; a < segments; a++) {
+ **hbone = bone;
+ ++*hbone;
+ }
+ }
+ return segments;
+ }
+ }
+ return 0;
+}
+
+static int vgroup_add_unique_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
+{
+ /* This group creates a vertex group to ob that has the
+ * same name as bone (provided the bone is skinnable).
+ * If such a vertex group aleady exist the routine exits.
+ */
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (!defgroup_find_name(ob, bone->name)) {
+ ED_vgroup_add_name(ob, bone->name);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
+{
+ /* Bones that are deforming
+ * are regarded to be "skinnable" and are eligible for
+ * auto-skinning.
+ *
+ * This function performs 2 functions:
+ *
+ * a) If the bone is skinnable, it creates
+ * a vertex group for ob that has
+ * the name of the skinnable bone
+ * (if one doesn't exist already).
+ * b) If the pointer data is non null,
+ * it is treated like a handle to a
+ * bDeformGroup pointer -- the
+ * bDeformGroup pointer is set to point
+ * to the deform group with the bone's
+ * name, and the pointer the handle
+ * points to is incremented to point to the
+ * next member of an array of pointers
+ * to bDeformGroups. This way we can loop using
+ * this function to construct an array of
+ * pointers to bDeformGroups, all with names
+ * of skinnable bones.
+ */
+ bDeformGroup ***hgroup, *defgroup = NULL;
+ int a, segments;
+ struct { Object *armob; void *list; int heat; } *data = datap;
+ int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
+ bArmature *arm = data->armob->data;
+
+ if (!wpmode || !(bone->flag & BONE_HIDDEN_P)) {
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name))
+ segments = bone->segments;
+ else
+ segments = 1;
+
+ if (!wpmode || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED)))
+ if (!(defgroup = defgroup_find_name(ob, bone->name)))
+ defgroup = ED_vgroup_add_name(ob, bone->name);
+
+ if (data->list != NULL) {
+ hgroup = (bDeformGroup ***) &data->list;
+
+ for (a = 0; a < segments; a++) {
+ **hgroup = defgroup;
+ ++*hgroup;
+ }
+ }
+ return segments;
+ }
+ }
+ return 0;
+}
+
+static void add_vgroups__mapFunc(void *userData, int index, const float co[3],
+ const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+{
+ /* DerivedMesh mapFunc for getting final coords in weight paint mode */
+
+ float (*verts)[3] = userData;
+ copy_v3_v3(verts[index], co);
+}
+
+static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist,
+ bDeformGroup **dgrouplist, bDeformGroup **dgroupflip,
+ float (*root)[3], float (*tip)[3], int *selected, float scale)
+{
+ /* Create vertex group weights from envelopes */
+
+ Bone *bone;
+ bDeformGroup *dgroup;
+ float distance;
+ int i, iflip, j;
+
+ /* for each vertex in the mesh */
+ for (i = 0; i < mesh->totvert; i++) {
+ iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, i) : 0;
+
+ /* for each skinnable bone */
+ for (j = 0; j < numbones; ++j) {
+ if (!selected[j])
+ continue;
+
+ bone = bonelist[j];
+ dgroup = dgrouplist[j];
+
+ /* store the distance-factor from the vertex to the bone */
+ distance = distfactor_to_bone(verts[i], root[j], tip[j],
+ bone->rad_head * scale, bone->rad_tail * scale, bone->dist * scale);
+
+ /* add the vert to the deform group if (weight != 0.0) */
+ if (distance != 0.0f)
+ ED_vgroup_vert_add(ob, dgroup, i, distance, WEIGHT_REPLACE);
+ else
+ ED_vgroup_vert_remove(ob, dgroup, i);
+
+ /* do same for mirror */
+ if (dgroupflip && dgroupflip[j] && iflip >= 0) {
+ if (distance != 0.0f)
+ ED_vgroup_vert_add(ob, dgroupflip[j], iflip, distance,
+ WEIGHT_REPLACE);
+ else
+ ED_vgroup_vert_remove(ob, dgroupflip[j], iflip);
+ }
+ }
+ }
+}
+
+static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, Object *par, int heat, int mirror)
+{
+ /* This functions implements the automatic computation of vertex group
+ * weights, either through envelopes or using a heat equilibrium.
+ *
+ * This function can be called both when parenting a mesh to an armature,
+ * or in weightpaint + posemode. In the latter case selection is taken
+ * into account and vertex weights can be mirrored.
+ *
+ * The mesh vertex positions used are either the final deformed coords
+ * from the derivedmesh in weightpaint mode, the final subsurf coords
+ * when parenting, or simply the original mesh coords.
+ */
+
+ bArmature *arm = par->data;
+ Bone **bonelist, *bone;
+ bDeformGroup **dgrouplist, **dgroupflip;
+ bDeformGroup *dgroup;
+ bPoseChannel *pchan;
+ Mesh *mesh;
+ Mat4 *bbone = NULL;
+ float (*root)[3], (*tip)[3], (*verts)[3];
+ int *selected;
+ int numbones, vertsfilled = 0, i, j, segments = 0;
+ int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
+ struct { Object *armob; void *list; int heat; } looper_data;
+
+ looper_data.armob = par;
+ looper_data.heat = heat;
+ looper_data.list = NULL;
+
+ /* count the number of skinnable bones */
+ numbones = bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb);
+
+ if (numbones == 0)
+ return;
+
+ if (ED_vgroup_data_create(ob->data) == FALSE)
+ return;
+
+ /* create an array of pointer to bones that are skinnable
+ * and fill it with all of the skinnable bones */
+ bonelist = MEM_callocN(numbones * sizeof(Bone *), "bonelist");
+ looper_data.list = bonelist;
+ bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb);
+
+ /* create an array of pointers to the deform groups that
+ * correspond to the skinnable bones (creating them
+ * as necessary. */
+ dgrouplist = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist");
+ dgroupflip = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgroupflip");
+
+ looper_data.list = dgrouplist;
+ bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable_cb);
+
+ /* create an array of root and tip positions transformed into
+ * global coords */
+ root = MEM_callocN(numbones * sizeof(float) * 3, "root");
+ tip = MEM_callocN(numbones * sizeof(float) * 3, "tip");
+ selected = MEM_callocN(numbones * sizeof(int), "selected");
+
+ for (j = 0; j < numbones; ++j) {
+ bone = bonelist[j];
+ dgroup = dgrouplist[j];
+
+ /* handle bbone */
+ if (heat) {
+ if (segments == 0) {
+ segments = 1;
+ bbone = NULL;
+
+ if ((par->pose) && (pchan = BKE_pose_channel_find_name(par->pose, bone->name))) {
+ if (bone->segments > 1) {
+ segments = bone->segments;
+ bbone = b_bone_spline_setup(pchan, 1);
+ }
+ }
+ }
+
+ segments--;
+ }
+
+ /* compute root and tip */
+ if (bbone) {
+ mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]);
+ if ((segments + 1) < bone->segments) {
+ mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]);
+ }
+ else {
+ copy_v3_v3(tip[j], bone->arm_tail);
+ }
+ }
+ else {
+ copy_v3_v3(root[j], bone->arm_head);
+ copy_v3_v3(tip[j], bone->arm_tail);
+ }
+
+ mul_m4_v3(par->obmat, root[j]);
+ mul_m4_v3(par->obmat, tip[j]);
+
+ /* set selected */
+ if (wpmode) {
+ if ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))
+ selected[j] = 1;
+ }
+ else
+ selected[j] = 1;
+
+ /* find flipped group */
+ if (dgroup && mirror) {
+ char name[MAXBONENAME];
+
+ // 0 = don't strip off number extensions
+ flip_side_name(name, dgroup->name, FALSE);
+ dgroupflip[j] = defgroup_find_name(ob, name);
+ }
+ }
+
+ /* create verts */
+ mesh = (Mesh *)ob->data;
+ verts = MEM_callocN(mesh->totvert * sizeof(*verts), "closestboneverts");
+
+ if (wpmode) {
+ /* if in weight paint mode, use final verts from derivedmesh */
+ DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+
+ if (dm->foreachMappedVert) {
+ dm->foreachMappedVert(dm, add_vgroups__mapFunc, (void *)verts);
+ vertsfilled = 1;
+ }
+
+ dm->release(dm);
+ }
+ else if (modifiers_findByType(ob, eModifierType_Subsurf)) {
+ /* is subsurf on? Lets use the verts on the limit surface then.
+ * = same amount of vertices as mesh, but vertices moved to the
+ * subsurfed position, like for 'optimal'. */
+ subsurf_calculate_limit_positions(mesh, verts);
+ vertsfilled = 1;
+ }
+
+ /* transform verts to global space */
+ for (i = 0; i < mesh->totvert; i++) {
+ if (!vertsfilled)
+ copy_v3_v3(verts[i], mesh->mvert[i].co);
+ mul_m4_v3(ob->obmat, verts[i]);
+ }
+
+ /* compute the weights based on gathered vertices and bones */
+ if (heat) {
+ const char *error = NULL;
+ heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip,
+ root, tip, selected, &error);
+
+ if (error) {
+ BKE_report(reports, RPT_WARNING, error);
+ }
+ }
+ else {
+ envelope_bone_weighting(ob, mesh, verts, numbones, bonelist, dgrouplist,
+ dgroupflip, root, tip, selected, mat4_to_scale(par->obmat));
+ }
+
+ /* only generated in some cases but can call anyway */
+ mesh_octree_table(ob, NULL, NULL, 'e');
+
+ /* free the memory allocated */
+ MEM_freeN(bonelist);
+ MEM_freeN(dgrouplist);
+ MEM_freeN(dgroupflip);
+ MEM_freeN(root);
+ MEM_freeN(tip);
+ MEM_freeN(selected);
+ MEM_freeN(verts);
+}
+
+void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob, Object *par, int mode, int mirror)
+{
+ /* Lets try to create some vertex groups
+ * based on the bones of the parent armature.
+ */
+ bArmature *arm = par->data;
+
+ if (mode == ARM_GROUPS_NAME) {
+ const int defbase_tot = BLI_countlist(&ob->defbase);
+ int defbase_add;
+ /* Traverse the bone list, trying to create empty vertex
+ * groups corresponding to the bone.
+ */
+ defbase_add = bone_looper(ob, arm->bonebase.first, NULL, vgroup_add_unique_bone_cb);
+
+ if (defbase_add) {
+ /* its possible there are DWeight's outside the range of the current
+ * objects deform groups, in this case the new groups wont be empty [#33889] */
+ ED_vgroup_data_clamp_range(ob->data, defbase_tot);
+ }
+ }
+ else if (mode == ARM_GROUPS_ENVELOPE || mode == ARM_GROUPS_AUTO) {
+ /* Traverse the bone list, trying to create vertex groups
+ * that are populated with the vertices for which the
+ * bone is closest.
+ */
+ add_verts_to_dgroups(reports, scene, ob, par, (mode == ARM_GROUPS_AUTO), mirror);
+ }
+}
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
new file mode 100644
index 00000000000..05f48ad73f4
--- /dev/null
+++ b/source/blender/editors/armature/armature_utils.c
@@ -0,0 +1,671 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/armature/armature_utils.c
+ * \ingroup edarmature
+ */
+
+#include "DNA_armature_types.h"
+#include "DNA_object_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BKE_armature.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_main.h"
+
+#include "ED_armature.h"
+#include "ED_util.h"
+
+#include "armature_intern.h"
+
+/* *************************************************************** */
+/* Validation */
+
+/* Sync selection to parent for connected children */
+void ED_armature_sync_selection(ListBase *edbo)
+{
+ EditBone *ebo;
+
+ for (ebo = edbo->first; ebo; ebo = ebo->next) {
+ /* if bone is not selectable, we shouldn't alter this setting... */
+ if ((ebo->flag & BONE_UNSELECTABLE) == 0) {
+ if ((ebo->flag & BONE_CONNECTED) && (ebo->parent)) {
+ if (ebo->parent->flag & BONE_TIPSEL)
+ ebo->flag |= BONE_ROOTSEL;
+ else
+ ebo->flag &= ~BONE_ROOTSEL;
+ }
+
+ if ((ebo->flag & BONE_TIPSEL) && (ebo->flag & BONE_ROOTSEL))
+ ebo->flag |= BONE_SELECTED;
+ else
+ ebo->flag &= ~BONE_SELECTED;
+ }
+ }
+}
+
+void ED_armature_validate_active(struct bArmature *arm)
+{
+ EditBone *ebone = arm->act_edbone;
+
+ if (ebone) {
+ if (ebone->flag & BONE_HIDDEN_A)
+ arm->act_edbone = NULL;
+ }
+}
+
+/* *************************************************************** */
+/* Bone Operations */
+
+/* XXX bone_looper is only to be used when we want to access settings
+ * (i.e. editability/visibility/selected) that context doesn't offer */
+int bone_looper(Object *ob, Bone *bone, void *data,
+ int (*bone_func)(Object *, Bone *, void *))
+{
+ /* We want to apply the function bone_func to every bone
+ * in an armature -- feed bone_looper the first bone and
+ * a pointer to the bone_func and watch it go!. The int count
+ * can be useful for counting bones with a certain property
+ * (e.g. skinnable)
+ */
+ int count = 0;
+
+ if (bone) {
+ /* only do bone_func if the bone is non null */
+ count += bone_func(ob, bone, data);
+
+ /* try to execute bone_func for the first child */
+ count += bone_looper(ob, bone->childbase.first, data, bone_func);
+
+ /* try to execute bone_func for the next bone at this
+ * depth of the recursion.
+ */
+ count += bone_looper(ob, bone->next, data, bone_func);
+ }
+
+ return count;
+}
+
+/* *************************************************************** */
+/* Bone Removal */
+
+void bone_free(bArmature *arm, EditBone *bone)
+{
+ if (arm->act_edbone == bone)
+ arm->act_edbone = NULL;
+
+ if (bone->prop) {
+ IDP_FreeProperty(bone->prop);
+ MEM_freeN(bone->prop);
+ }
+
+ BLI_freelinkN(arm->edbo, bone);
+}
+
+void ED_armature_edit_bone_remove(bArmature *arm, EditBone *exBone)
+{
+ EditBone *curBone;
+
+ /* Find any bones that refer to this bone */
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (curBone->parent == exBone) {
+ curBone->parent = exBone->parent;
+ curBone->flag &= ~BONE_CONNECTED;
+ }
+ }
+
+ bone_free(arm, exBone);
+}
+
+/* *************************************************************** */
+/* Mirroring */
+
+/* context: editmode armature */
+EditBone *ED_armature_bone_get_mirrored(ListBase *edbo, EditBone *ebo)
+{
+ EditBone *eboflip = NULL;
+ char name[MAXBONENAME];
+
+ if (ebo == NULL)
+ return NULL;
+
+ flip_side_name(name, ebo->name, FALSE);
+
+ for (eboflip = edbo->first; eboflip; eboflip = eboflip->next) {
+ if (ebo != eboflip) {
+ if (!strcmp(name, eboflip->name))
+ break;
+ }
+ }
+
+ return eboflip;
+}
+
+/* ------------------------------------- */
+
+/* helper function for tools to work on mirrored parts.
+ * it leaves mirrored bones selected then too, which is a good indication of what happened */
+void armature_select_mirrored(bArmature *arm)
+{
+ /* Select mirrored bones */
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ EditBone *curBone, *ebone_mirr;
+
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (arm->layer & curBone->layer) {
+ if (curBone->flag & BONE_SELECTED) {
+ ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone);
+ if (ebone_mirr)
+ ebone_mirr->flag |= BONE_SELECTED;
+ }
+ }
+ }
+ }
+
+}
+
+void armature_tag_select_mirrored(bArmature *arm)
+{
+ EditBone *curBone;
+
+ /* always untag */
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ curBone->flag &= ~BONE_DONE;
+ }
+
+ /* Select mirrored bones */
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (arm->layer & curBone->layer) {
+ if (curBone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) {
+ EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone);
+ if (ebone_mirr && (ebone_mirr->flag & BONE_SELECTED) == 0) {
+ ebone_mirr->flag |= BONE_DONE;
+ }
+ }
+ }
+ }
+
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (curBone->flag & BONE_DONE) {
+ EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone);
+ curBone->flag |= ebone_mirr->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
+ }
+ }
+ }
+}
+
+/* only works when tagged */
+void armature_tag_unselect(bArmature *arm)
+{
+ EditBone *curBone;
+
+ for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
+ if (curBone->flag & BONE_DONE) {
+ curBone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL | BONE_DONE);
+ }
+ }
+}
+
+/* ------------------------------------- */
+
+/* if editbone (partial) selected, copy data */
+/* context; editmode armature, with mirror editing enabled */
+void transform_armature_mirror_update(Object *obedit)
+{
+ bArmature *arm = obedit->data;
+ EditBone *ebo, *eboflip;
+
+ for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ /* no layer check, correct mirror is more important */
+ if (ebo->flag & (BONE_TIPSEL | BONE_ROOTSEL)) {
+ eboflip = ED_armature_bone_get_mirrored(arm->edbo, ebo);
+
+ if (eboflip) {
+ /* we assume X-axis flipping for now */
+ if (ebo->flag & BONE_TIPSEL) {
+ EditBone *children;
+
+ eboflip->tail[0] = -ebo->tail[0];
+ eboflip->tail[1] = ebo->tail[1];
+ eboflip->tail[2] = ebo->tail[2];
+ eboflip->rad_tail = ebo->rad_tail;
+ eboflip->roll = -ebo->roll;
+
+ /* Also move connected children, in case children's name aren't mirrored properly */
+ for (children = arm->edbo->first; children; children = children->next) {
+ if (children->parent == eboflip && children->flag & BONE_CONNECTED) {
+ copy_v3_v3(children->head, eboflip->tail);
+ children->rad_head = ebo->rad_tail;
+ }
+ }
+ }
+ if (ebo->flag & BONE_ROOTSEL) {
+ eboflip->head[0] = -ebo->head[0];
+ eboflip->head[1] = ebo->head[1];
+ eboflip->head[2] = ebo->head[2];
+ eboflip->rad_head = ebo->rad_head;
+ eboflip->roll = -ebo->roll;
+
+ /* Also move connected parent, in case parent's name isn't mirrored properly */
+ if (eboflip->parent && eboflip->flag & BONE_CONNECTED) {
+ EditBone *parent = eboflip->parent;
+ copy_v3_v3(parent->tail, eboflip->head);
+ parent->rad_tail = ebo->rad_head;
+ }
+ }
+ if (ebo->flag & BONE_SELECTED) {
+ eboflip->dist = ebo->dist;
+ eboflip->roll = -ebo->roll;
+ eboflip->xwidth = ebo->xwidth;
+ eboflip->zwidth = ebo->zwidth;
+ }
+ }
+ }
+ }
+}
+
+/* *************************************************************** */
+/* Armature EditMode Conversions */
+
+/* converts Bones to EditBone list, used for tools as well */
+EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone *actBone)
+{
+ EditBone *eBone;
+ EditBone *eBoneAct = NULL;
+ EditBone *eBoneTest = NULL;
+ Bone *curBone;
+
+ for (curBone = bones->first; curBone; curBone = curBone->next) {
+ eBone = MEM_callocN(sizeof(EditBone), "make_editbone");
+
+ /* Copy relevant data from bone to eBone */
+ eBone->parent = parent;
+ BLI_strncpy(eBone->name, curBone->name, sizeof(eBone->name));
+ eBone->flag = curBone->flag;
+
+ /* fix selection flags */
+ if (eBone->flag & BONE_SELECTED) {
+ /* if the bone is selected the copy its root selection to the parents tip */
+ eBone->flag |= BONE_TIPSEL;
+ if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
+ eBone->parent->flag |= BONE_TIPSEL;
+ eBone->flag &= ~BONE_ROOTSEL; /* this is ignored when there is a connected parent, so unset it */
+ }
+ else {
+ eBone->flag |= BONE_ROOTSEL;
+ }
+ }
+ else {
+ /* if the bone is not selected, but connected to its parent
+ * copy the parents tip selection state */
+ if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
+ /* selecting with the mouse gives this behavior */
+ if (eBone->parent->flag & BONE_TIPSEL) {
+ eBone->flag |= BONE_ROOTSEL;
+ }
+ else {
+ eBone->flag &= ~BONE_ROOTSEL;
+ }
+
+ /* probably not selected but just in case */
+ eBone->flag &= ~BONE_TIPSEL;
+ }
+ }
+
+ copy_v3_v3(eBone->head, curBone->arm_head);
+ copy_v3_v3(eBone->tail, curBone->arm_tail);
+ eBone->roll = curBone->arm_roll;
+
+ /* rest of stuff copy */
+ eBone->length = curBone->length;
+ eBone->dist = curBone->dist;
+ eBone->weight = curBone->weight;
+ eBone->xwidth = curBone->xwidth;
+ eBone->zwidth = curBone->zwidth;
+ eBone->ease1 = curBone->ease1;
+ eBone->ease2 = curBone->ease2;
+ eBone->rad_head = curBone->rad_head;
+ eBone->rad_tail = curBone->rad_tail;
+ eBone->segments = curBone->segments;
+ eBone->layer = curBone->layer;
+
+ if (curBone->prop)
+ eBone->prop = IDP_CopyProperty(curBone->prop);
+
+ BLI_addtail(edbo, eBone);
+
+ /* Add children if necessary */
+ if (curBone->childbase.first) {
+ eBoneTest = make_boneList(edbo, &curBone->childbase, eBone, actBone);
+ if (eBoneTest)
+ eBoneAct = eBoneTest;
+ }
+
+ if (curBone == actBone)
+ eBoneAct = eBone;
+ }
+
+ return eBoneAct;
+}
+
+/* nasty stuff for converting roll in editbones into bones */
+/* also sets restposition in armature (arm_mat) */
+static void fix_bonelist_roll(ListBase *bonelist, ListBase *editbonelist)
+{
+ Bone *curBone;
+ EditBone *ebone;
+ float premat[3][3];
+ float postmat[3][3];
+ float difmat[3][3];
+ float imat[3][3];
+ float delta[3];
+
+ for (curBone = bonelist->first; curBone; curBone = curBone->next) {
+ /* sets local matrix and arm_mat (restpos) */
+ BKE_armature_where_is_bone(curBone, curBone->parent);
+
+ /* Find the associated editbone */
+ for (ebone = editbonelist->first; ebone; ebone = ebone->next)
+ if ((Bone *)ebone->temp == curBone)
+ break;
+
+ if (ebone) {
+ /* Get the ebone premat */
+ sub_v3_v3v3(delta, ebone->tail, ebone->head);
+ vec_roll_to_mat3(delta, ebone->roll, premat);
+
+ /* Get the bone postmat */
+ copy_m3_m4(postmat, curBone->arm_mat);
+
+ invert_m3_m3(imat, premat);
+ mul_m3_m3m3(difmat, imat, postmat);
+#if 0
+ printf("Bone %s\n", curBone->name);
+ print_m4("premat", premat);
+ print_m4("postmat", postmat);
+ print_m4("difmat", difmat);
+ printf("Roll = %f\n", RAD2DEGF(-atan2(difmat[2][0], difmat[2][2])));
+#endif
+ curBone->roll = (float)-atan2(difmat[2][0], difmat[2][2]);
+
+ /* and set restposition again */
+ BKE_armature_where_is_bone(curBone, curBone->parent);
+ }
+ fix_bonelist_roll(&curBone->childbase, editbonelist);
+ }
+}
+
+/* put EditMode back in Object */
+void ED_armature_from_edit(Object *obedit)
+{
+ bArmature *arm = obedit->data;
+ EditBone *eBone, *neBone;
+ Bone *newBone;
+ Object *obt;
+
+ /* armature bones */
+ BKE_armature_bonelist_free(&arm->bonebase);
+
+ /* remove zero sized bones, this gives instable restposes */
+ for (eBone = arm->edbo->first; eBone; eBone = neBone) {
+ float len = len_v3v3(eBone->head, eBone->tail);
+ neBone = eBone->next;
+ if (len <= 0.000001f) { /* FLT_EPSILON is too large? */
+ EditBone *fBone;
+
+ /* Find any bones that refer to this bone */
+ for (fBone = arm->edbo->first; fBone; fBone = fBone->next) {
+ if (fBone->parent == eBone)
+ fBone->parent = eBone->parent;
+ }
+ if (G.debug & G_DEBUG)
+ printf("Warning: removed zero sized bone: %s\n", eBone->name);
+ bone_free(arm, eBone);
+ }
+ }
+
+ /* Copy the bones from the editData into the armature */
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ newBone = MEM_callocN(sizeof(Bone), "bone");
+ eBone->temp = newBone; /* Associate the real Bones with the EditBones */
+
+ BLI_strncpy(newBone->name, eBone->name, sizeof(newBone->name));
+ copy_v3_v3(newBone->arm_head, eBone->head);
+ copy_v3_v3(newBone->arm_tail, eBone->tail);
+ newBone->arm_roll = eBone->roll;
+
+ newBone->flag = eBone->flag;
+
+ if (eBone == arm->act_edbone) {
+ /* don't change active selection, this messes up separate which uses
+ * editmode toggle and can separate active bone which is de-selected originally */
+ /* newBone->flag |= BONE_SELECTED; */ /* important, editbones can be active with only 1 point selected */
+ arm->act_edbone = NULL;
+ arm->act_bone = newBone;
+ }
+ newBone->roll = 0.0f;
+
+ newBone->weight = eBone->weight;
+ newBone->dist = eBone->dist;
+
+ newBone->xwidth = eBone->xwidth;
+ newBone->zwidth = eBone->zwidth;
+ newBone->ease1 = eBone->ease1;
+ newBone->ease2 = eBone->ease2;
+ newBone->rad_head = eBone->rad_head;
+ newBone->rad_tail = eBone->rad_tail;
+ newBone->segments = eBone->segments;
+ newBone->layer = eBone->layer;
+
+ if (eBone->prop)
+ newBone->prop = IDP_CopyProperty(eBone->prop);
+ }
+
+ /* Fix parenting in a separate pass to ensure ebone->bone connections
+ * are valid at this point */
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ newBone = (Bone *)eBone->temp;
+ if (eBone->parent) {
+ newBone->parent = (Bone *)eBone->parent->temp;
+ BLI_addtail(&newBone->parent->childbase, newBone);
+
+ {
+ float M_parentRest[3][3];
+ float iM_parentRest[3][3];
+ float delta[3];
+
+ /* Get the parent's matrix (rotation only) */
+ sub_v3_v3v3(delta, eBone->parent->tail, eBone->parent->head);
+ vec_roll_to_mat3(delta, eBone->parent->roll, M_parentRest);
+
+ /* Invert the parent matrix */
+ invert_m3_m3(iM_parentRest, M_parentRest);
+
+ /* Get the new head and tail */
+ sub_v3_v3v3(newBone->head, eBone->head, eBone->parent->tail);
+ sub_v3_v3v3(newBone->tail, eBone->tail, eBone->parent->tail);
+
+ mul_m3_v3(iM_parentRest, newBone->head);
+ mul_m3_v3(iM_parentRest, newBone->tail);
+ }
+ }
+ /* ...otherwise add this bone to the armature's bonebase */
+ else {
+ copy_v3_v3(newBone->head, eBone->head);
+ copy_v3_v3(newBone->tail, eBone->tail);
+ BLI_addtail(&arm->bonebase, newBone);
+ }
+ }
+
+ /* Make a pass through the new armature to fix rolling */
+ /* also builds restposition again (like BKE_armature_where_is) */
+ fix_bonelist_roll(&arm->bonebase, arm->edbo);
+
+ /* so all users of this armature should get rebuilt */
+ for (obt = G.main->object.first; obt; obt = obt->id.next) {
+ if (obt->data == arm)
+ BKE_pose_rebuild(obt, arm);
+ }
+
+ DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+}
+
+void ED_armature_edit_free(struct Object *ob)
+{
+ bArmature *arm = ob->data;
+ EditBone *eBone;
+
+ /* Clear the editbones list */
+ if (arm->edbo) {
+ if (arm->edbo->first) {
+ for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ if (eBone->prop) {
+ IDP_FreeProperty(eBone->prop);
+ MEM_freeN(eBone->prop);
+ }
+ }
+
+ BLI_freelistN(arm->edbo);
+ }
+ MEM_freeN(arm->edbo);
+ arm->edbo = NULL;
+ }
+}
+
+/* Put armature in EditMode */
+void ED_armature_to_edit(Object *ob)
+{
+ bArmature *arm = ob->data;
+
+ ED_armature_edit_free(ob);
+ arm->edbo = MEM_callocN(sizeof(ListBase), "edbo armature");
+ arm->act_edbone = make_boneList(arm->edbo, &arm->bonebase, NULL, arm->act_bone);
+ arm->act_bone = NULL;
+
+// BIF_freeTemplates(); /* force template update when entering editmode */
+}
+
+/* *************************************************************** */
+/* Undo for Armature EditMode*/
+
+typedef struct UndoArmature {
+ EditBone *act_edbone;
+ ListBase lb;
+} UndoArmature;
+
+static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data))
+{
+ UndoArmature *uarm = uarmv;
+ bArmature *arm = armv;
+ EditBone *ebo, *newebo;
+
+ BLI_freelistN(arm->edbo);
+
+ /* copy */
+ for (ebo = uarm->lb.first; ebo; ebo = ebo->next) {
+ newebo = MEM_dupallocN(ebo);
+ ebo->temp = newebo;
+ BLI_addtail(arm->edbo, newebo);
+ }
+
+ /* active bone */
+ if (uarm->act_edbone) {
+ ebo = uarm->act_edbone;
+ arm->act_edbone = ebo->temp;
+ }
+ else
+ arm->act_edbone = NULL;
+
+ /* set pointers */
+ for (newebo = arm->edbo->first; newebo; newebo = newebo->next) {
+ if (newebo->parent) newebo->parent = newebo->parent->temp;
+ }
+ /* be sure they don't hang ever */
+ for (newebo = arm->edbo->first; newebo; newebo = newebo->next) {
+ newebo->temp = NULL;
+ }
+}
+
+static void *editBones_to_undoBones(void *armv, void *UNUSED(obdata))
+{
+ bArmature *arm = armv;
+ UndoArmature *uarm;
+ EditBone *ebo, *newebo;
+
+ uarm = MEM_callocN(sizeof(UndoArmature), "listbase undo");
+
+ /* copy */
+ for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ newebo = MEM_dupallocN(ebo);
+ ebo->temp = newebo;
+ BLI_addtail(&uarm->lb, newebo);
+ }
+
+ /* active bone */
+ if (arm->act_edbone) {
+ ebo = arm->act_edbone;
+ uarm->act_edbone = ebo->temp;
+ }
+
+ /* set pointers */
+ for (newebo = uarm->lb.first; newebo; newebo = newebo->next) {
+ if (newebo->parent) newebo->parent = newebo->parent->temp;
+ }
+
+ return uarm;
+}
+
+static void free_undoBones(void *uarmv)
+{
+ UndoArmature *uarm = uarmv;
+
+ BLI_freelistN(&uarm->lb);
+ MEM_freeN(uarm);
+}
+
+static void *get_armature_edit(bContext *C)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit && obedit->type == OB_ARMATURE) {
+ return obedit->data;
+ }
+ return NULL;
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_armature(bContext *C, const char *name)
+{
+ // XXX solve getdata()
+ undo_editmode_push(C, name, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL);
+}
diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c
deleted file mode 100644
index 2eac6ba87ee..00000000000
--- a/source/blender/editors/armature/editarmature.c
+++ /dev/null
@@ -1,6197 +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.
- *
- * Contributor(s): Blender Foundation, 2002-2009 full recode.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/armature/editarmature.c
- * \ingroup edarmature
- */
-
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <math.h>
-#include <float.h>
-#include <assert.h>
-
-
-#include "DNA_anim_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-
-#include "BKE_animsys.h"
-#include "BKE_action.h"
-#include "BKE_armature.h"
-#include "BKE_constraint.h"
-#include "BKE_context.h"
-#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_global.h"
-#include "BKE_idprop.h"
-#include "BKE_main.h"
-#include "BKE_object.h"
-#include "BKE_report.h"
-#include "BKE_subsurf.h"
-#include "BKE_modifier.h"
-#include "DNA_object_types.h"
-
-#include "BIF_gl.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_armature.h"
-#include "ED_keyframing.h"
-#include "ED_mesh.h"
-#include "ED_object.h"
-#include "ED_screen.h"
-#include "ED_util.h"
-#include "ED_view3d.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "armature_intern.h"
-#include "meshlaplacian.h"
-
-#if 0
-#include "reeb.h"
-#endif
-
-/* **************** tools on Editmode Armature **************** */
-
-/* Sync selection to parent for connected children */
-void ED_armature_sync_selection(ListBase *edbo)
-{
- EditBone *ebo;
-
- for (ebo = edbo->first; ebo; ebo = ebo->next) {
- /* if bone is not selectable, we shouldn't alter this setting... */
- if ((ebo->flag & BONE_UNSELECTABLE) == 0) {
- if ((ebo->flag & BONE_CONNECTED) && (ebo->parent)) {
- if (ebo->parent->flag & BONE_TIPSEL)
- ebo->flag |= BONE_ROOTSEL;
- else
- ebo->flag &= ~BONE_ROOTSEL;
- }
-
- if ((ebo->flag & BONE_TIPSEL) && (ebo->flag & BONE_ROOTSEL))
- ebo->flag |= BONE_SELECTED;
- else
- ebo->flag &= ~BONE_SELECTED;
- }
- }
-}
-
-void ED_armature_validate_active(struct bArmature *arm)
-{
- EditBone *ebone = arm->act_edbone;
-
- if (ebone) {
- if (ebone->flag & BONE_HIDDEN_A)
- arm->act_edbone = NULL;
- }
-}
-
-static void bone_free(bArmature *arm, EditBone *bone)
-{
- if (arm->act_edbone == bone)
- arm->act_edbone = NULL;
-
- if (bone->prop) {
- IDP_FreeProperty(bone->prop);
- MEM_freeN(bone->prop);
- }
-
- BLI_freelinkN(arm->edbo, bone);
-}
-
-void ED_armature_edit_bone_remove(bArmature *arm, EditBone *exBone)
-{
- EditBone *curBone;
-
- /* Find any bones that refer to this bone */
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (curBone->parent == exBone) {
- curBone->parent = exBone->parent;
- curBone->flag &= ~BONE_CONNECTED;
- }
- }
-
- bone_free(arm, exBone);
-}
-
-/* context: editmode armature */
-EditBone *ED_armature_bone_get_mirrored(ListBase *edbo, EditBone *ebo)
-{
- EditBone *eboflip = NULL;
- char name[MAXBONENAME];
-
- if (ebo == NULL)
- return NULL;
-
- flip_side_name(name, ebo->name, FALSE);
-
- for (eboflip = edbo->first; eboflip; eboflip = eboflip->next) {
- if (ebo != eboflip) {
- if (!strcmp(name, eboflip->name))
- break;
- }
- }
-
- return eboflip;
-}
-
-/* helper function for tools to work on mirrored parts.
- * it leaves mirrored bones selected then too, which is a good indication of what happened */
-static void armature_select_mirrored(bArmature *arm)
-{
- /* Select mirrored bones */
- if (arm->flag & ARM_MIRROR_EDIT) {
- EditBone *curBone, *ebone_mirr;
-
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (arm->layer & curBone->layer) {
- if (curBone->flag & BONE_SELECTED) {
- ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone);
- if (ebone_mirr)
- ebone_mirr->flag |= BONE_SELECTED;
- }
- }
- }
- }
-
-}
-
-static void armature_tag_select_mirrored(bArmature *arm)
-{
- EditBone *curBone;
-
- /* always untag */
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- curBone->flag &= ~BONE_DONE;
- }
-
- /* Select mirrored bones */
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (arm->layer & curBone->layer) {
- if (curBone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) {
- EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone);
- if (ebone_mirr && (ebone_mirr->flag & BONE_SELECTED) == 0) {
- ebone_mirr->flag |= BONE_DONE;
- }
- }
- }
- }
-
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (curBone->flag & BONE_DONE) {
- EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, curBone);
- curBone->flag |= ebone_mirr->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
- }
- }
- }
-}
-
-
-/* only works when tagged */
-static void armature_tag_unselect(bArmature *arm)
-{
- EditBone *curBone;
-
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (curBone->flag & BONE_DONE) {
- curBone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL | BONE_DONE);
- }
- }
-}
-
-/* converts Bones to EditBone list, used for tools as well */
-EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone *actBone)
-{
- EditBone *eBone;
- EditBone *eBoneAct = NULL;
- EditBone *eBoneTest = NULL;
- Bone *curBone;
-
- for (curBone = bones->first; curBone; curBone = curBone->next) {
- eBone = MEM_callocN(sizeof(EditBone), "make_editbone");
-
- /* Copy relevant data from bone to eBone */
- eBone->parent = parent;
- BLI_strncpy(eBone->name, curBone->name, sizeof(eBone->name));
- eBone->flag = curBone->flag;
-
- /* fix selection flags */
-
- if (eBone->flag & BONE_SELECTED) {
- /* if the bone is selected the copy its root selection to the parents tip */
- eBone->flag |= BONE_TIPSEL;
- if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
- eBone->parent->flag |= BONE_TIPSEL;
- eBone->flag &= ~BONE_ROOTSEL; /* this is ignored when there is a connected parent, so unset it */
- }
- else {
- eBone->flag |= BONE_ROOTSEL;
- }
- }
- else {
- /* if the bone is not selected, but connected to its parent
- * copy the parents tip selection state */
- if (eBone->parent && (eBone->flag & BONE_CONNECTED)) {
- /* selecting with the mouse gives this behavior */
- if (eBone->parent->flag & BONE_TIPSEL) {
- eBone->flag |= BONE_ROOTSEL;
- }
- else {
- eBone->flag &= ~BONE_ROOTSEL;
- }
-
- /* probably not selected but just in case */
- eBone->flag &= ~BONE_TIPSEL;
- }
- }
-
- copy_v3_v3(eBone->head, curBone->arm_head);
- copy_v3_v3(eBone->tail, curBone->arm_tail);
- eBone->roll = curBone->arm_roll;
-
- /* rest of stuff copy */
- eBone->length = curBone->length;
- eBone->dist = curBone->dist;
- eBone->weight = curBone->weight;
- eBone->xwidth = curBone->xwidth;
- eBone->zwidth = curBone->zwidth;
- eBone->ease1 = curBone->ease1;
- eBone->ease2 = curBone->ease2;
- eBone->rad_head = curBone->rad_head;
- eBone->rad_tail = curBone->rad_tail;
- eBone->segments = curBone->segments;
- eBone->layer = curBone->layer;
-
- if (curBone->prop)
- eBone->prop = IDP_CopyProperty(curBone->prop);
-
- BLI_addtail(edbo, eBone);
-
- /* Add children if necessary */
- if (curBone->childbase.first) {
- eBoneTest = make_boneList(edbo, &curBone->childbase, eBone, actBone);
- if (eBoneTest)
- eBoneAct = eBoneTest;
- }
-
- if (curBone == actBone)
- eBoneAct = eBone;
- }
-
- return eBoneAct;
-}
-
-/* nasty stuff for converting roll in editbones into bones */
-/* also sets restposition in armature (arm_mat) */
-static void fix_bonelist_roll(ListBase *bonelist, ListBase *editbonelist)
-{
- Bone *curBone;
- EditBone *ebone;
- float premat[3][3];
- float postmat[3][3];
- float difmat[3][3];
- float imat[3][3];
- float delta[3];
-
- for (curBone = bonelist->first; curBone; curBone = curBone->next) {
- /* sets local matrix and arm_mat (restpos) */
- BKE_armature_where_is_bone(curBone, curBone->parent);
-
- /* Find the associated editbone */
- for (ebone = editbonelist->first; ebone; ebone = ebone->next)
- if ((Bone *)ebone->temp == curBone)
- break;
-
- if (ebone) {
- /* Get the ebone premat */
- sub_v3_v3v3(delta, ebone->tail, ebone->head);
- vec_roll_to_mat3(delta, ebone->roll, premat);
-
- /* Get the bone postmat */
- copy_m3_m4(postmat, curBone->arm_mat);
-
- invert_m3_m3(imat, premat);
- mul_m3_m3m3(difmat, imat, postmat);
-#if 0
- printf("Bone %s\n", curBone->name);
- print_m4("premat", premat);
- print_m4("postmat", postmat);
- print_m4("difmat", difmat);
- printf("Roll = %f\n", RAD2DEGF(-atan2(difmat[2][0], difmat[2][2])));
-#endif
- curBone->roll = (float)-atan2(difmat[2][0], difmat[2][2]);
-
- /* and set restposition again */
- BKE_armature_where_is_bone(curBone, curBone->parent);
- }
- fix_bonelist_roll(&curBone->childbase, editbonelist);
- }
-}
-
-/* put EditMode back in Object */
-void ED_armature_from_edit(Object *obedit)
-{
- bArmature *arm = obedit->data;
- EditBone *eBone, *neBone;
- Bone *newBone;
- Object *obt;
-
- /* armature bones */
- BKE_armature_bonelist_free(&arm->bonebase);
-
- /* remove zero sized bones, this gives instable restposes */
- for (eBone = arm->edbo->first; eBone; eBone = neBone) {
- float len = len_v3v3(eBone->head, eBone->tail);
- neBone = eBone->next;
- if (len <= 0.000001f) { /* FLT_EPSILON is too large? */
- EditBone *fBone;
-
- /* Find any bones that refer to this bone */
- for (fBone = arm->edbo->first; fBone; fBone = fBone->next) {
- if (fBone->parent == eBone)
- fBone->parent = eBone->parent;
- }
- if (G.debug & G_DEBUG)
- printf("Warning: removed zero sized bone: %s\n", eBone->name);
- bone_free(arm, eBone);
- }
- }
-
- /* Copy the bones from the editData into the armature */
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- newBone = MEM_callocN(sizeof(Bone), "bone");
- eBone->temp = newBone; /* Associate the real Bones with the EditBones */
-
- BLI_strncpy(newBone->name, eBone->name, sizeof(newBone->name));
- copy_v3_v3(newBone->arm_head, eBone->head);
- copy_v3_v3(newBone->arm_tail, eBone->tail);
- newBone->arm_roll = eBone->roll;
-
- newBone->flag = eBone->flag;
-
- if (eBone == arm->act_edbone) {
- /* don't change active selection, this messes up separate which uses
- * editmode toggle and can separate active bone which is de-selected originally */
- /* newBone->flag |= BONE_SELECTED; */ /* important, editbones can be active with only 1 point selected */
- arm->act_edbone = NULL;
- arm->act_bone = newBone;
- }
- newBone->roll = 0.0f;
-
- newBone->weight = eBone->weight;
- newBone->dist = eBone->dist;
-
- newBone->xwidth = eBone->xwidth;
- newBone->zwidth = eBone->zwidth;
- newBone->ease1 = eBone->ease1;
- newBone->ease2 = eBone->ease2;
- newBone->rad_head = eBone->rad_head;
- newBone->rad_tail = eBone->rad_tail;
- newBone->segments = eBone->segments;
- newBone->layer = eBone->layer;
-
- if (eBone->prop)
- newBone->prop = IDP_CopyProperty(eBone->prop);
- }
-
- /* Fix parenting in a separate pass to ensure ebone->bone connections
- * are valid at this point */
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- newBone = (Bone *)eBone->temp;
- if (eBone->parent) {
- newBone->parent = (Bone *)eBone->parent->temp;
- BLI_addtail(&newBone->parent->childbase, newBone);
-
- {
- float M_parentRest[3][3];
- float iM_parentRest[3][3];
- float delta[3];
-
- /* Get the parent's matrix (rotation only) */
- sub_v3_v3v3(delta, eBone->parent->tail, eBone->parent->head);
- vec_roll_to_mat3(delta, eBone->parent->roll, M_parentRest);
-
- /* Invert the parent matrix */
- invert_m3_m3(iM_parentRest, M_parentRest);
-
- /* Get the new head and tail */
- sub_v3_v3v3(newBone->head, eBone->head, eBone->parent->tail);
- sub_v3_v3v3(newBone->tail, eBone->tail, eBone->parent->tail);
-
- mul_m3_v3(iM_parentRest, newBone->head);
- mul_m3_v3(iM_parentRest, newBone->tail);
- }
- }
- /* ...otherwise add this bone to the armature's bonebase */
- else {
- copy_v3_v3(newBone->head, eBone->head);
- copy_v3_v3(newBone->tail, eBone->tail);
- BLI_addtail(&arm->bonebase, newBone);
- }
- }
-
- /* Make a pass through the new armature to fix rolling */
- /* also builds restposition again (like BKE_armature_where_is) */
- fix_bonelist_roll(&arm->bonebase, arm->edbo);
-
- /* so all users of this armature should get rebuilt */
- for (obt = G.main->object.first; obt; obt = obt->id.next) {
- if (obt->data == arm)
- BKE_pose_rebuild(obt, arm);
- }
-
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
-}
-
-void ED_armature_apply_transform(Object *ob, float mat[4][4])
-{
- EditBone *ebone;
- bArmature *arm = ob->data;
- float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */
- float mat3[3][3];
-
- copy_m3_m4(mat3, mat);
- normalize_m3(mat3);
-
- /* Put the armature into editmode */
- ED_armature_to_edit(ob);
-
- /* Do the rotations */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- float delta[3], tmat[3][3];
-
- /* find the current bone's roll matrix */
- sub_v3_v3v3(delta, ebone->tail, ebone->head);
- vec_roll_to_mat3(delta, ebone->roll, tmat);
-
- /* transform the roll matrix */
- mul_m3_m3m3(tmat, mat3, tmat);
-
- /* transform the bone */
- mul_m4_v3(mat, ebone->head);
- mul_m4_v3(mat, ebone->tail);
-
- /* apply the transfiormed roll back */
- mat3_to_vec_roll(tmat, NULL, &ebone->roll);
-
- ebone->rad_head *= scale;
- ebone->rad_tail *= scale;
- ebone->dist *= scale;
-
- /* we could be smarter and scale by the matrix along the x & z axis */
- ebone->xwidth *= scale;
- ebone->zwidth *= scale;
- }
-
- /* Turn the list into an armature */
- ED_armature_from_edit(ob);
- ED_armature_edit_free(ob);
-}
-
-/* exported for use in editors/object/ */
-/* 0 == do center, 1 == center new, 2 == center cursor */
-void docenter_armature(Scene *scene, Object *ob, float cursor[3], int centermode, int around)
-{
- Object *obedit = scene->obedit; // XXX get from context
- EditBone *ebone;
- bArmature *arm = ob->data;
- float cent[3];
-
- /* Put the armature into editmode */
- if (ob != obedit) {
- ED_armature_to_edit(ob);
- obedit = NULL; /* we cant use this so behave as if there is no obedit */
- }
-
- /* Find the centerpoint */
- if (centermode == 2) {
- copy_v3_v3(cent, cursor);
- invert_m4_m4(ob->imat, ob->obmat);
- mul_m4_v3(ob->imat, cent);
- }
- else {
- if (around == V3D_CENTROID) {
- int total = 0;
- zero_v3(cent);
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- total += 2;
- add_v3_v3(cent, ebone->head);
- add_v3_v3(cent, ebone->tail);
- }
- if (total) {
- mul_v3_fl(cent, 1.0f / (float)total);
- }
- }
- else {
- float min[3], max[3];
- INIT_MINMAX(min, max);
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- minmax_v3v3_v3(min, max, ebone->head);
- minmax_v3v3_v3(min, max, ebone->tail);
- }
- mid_v3_v3v3(cent, min, max);
- }
- }
-
- /* Do the adjustments */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- sub_v3_v3(ebone->head, cent);
- sub_v3_v3(ebone->tail, cent);
- }
-
- /* Turn the list into an armature */
- if (obedit == NULL) {
- ED_armature_from_edit(ob);
- ED_armature_edit_free(ob);
- }
-
- /* Adjust object location for new centerpoint */
- if (centermode && obedit == NULL) {
- mul_mat3_m4_v3(ob->obmat, cent); /* ommit translation part */
- add_v3_v3(ob->loc, cent);
- }
-}
-
-/* ---------------------- */
-
-/* checks if an EditBone with a matching name already, returning the matching bone if it exists */
-static EditBone *editbone_name_exists(ListBase *edbo, const char *name)
-{
- return BLI_findstring(edbo, name, offsetof(EditBone, name));
-}
-
-/* note: there's a unique_bone_name() too! */
-static int editbone_unique_check(void *arg, const char *name)
-{
- struct {ListBase *lb; void *bone; } *data = arg;
- EditBone *dupli = editbone_name_exists(data->lb, name);
- return dupli && dupli != data->bone;
-}
-
-void unique_editbone_name(ListBase *edbo, char *name, EditBone *bone)
-{
- struct {ListBase *lb; void *bone; } data;
- data.lb = edbo;
- data.bone = bone;
-
- BLI_uniquename_cb(editbone_unique_check, &data, "Bone", '.', name, sizeof(bone->name));
-}
-
-/* helper for apply_armature_pose2bones - fixes parenting of objects that are bone-parented to armature */
-static void applyarmature_fix_boneparents(Scene *scene, Object *armob)
-{
- Object workob, *ob;
-
- /* go through all objects in database */
- for (ob = G.main->object.first; ob; ob = ob->id.next) {
- /* if parent is bone in this armature, apply corrections */
- if ((ob->parent == armob) && (ob->partype == PARBONE)) {
- /* apply current transform from parent (not yet destroyed),
- * then calculate new parent inverse matrix
- */
- BKE_object_apply_mat4(ob, ob->obmat, FALSE, FALSE);
-
- BKE_object_workob_calc_parent(scene, ob, &workob);
- invert_m4_m4(ob->parentinv, workob.obmat);
- }
- }
-}
-
-/* set the current pose as the restpose */
-static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object
- bArmature *arm = BKE_armature_from_object(ob);
- bPose *pose;
- bPoseChannel *pchan;
- EditBone *curbone;
-
- /* don't check if editmode (should be done by caller) */
- if (ob->type != OB_ARMATURE)
- return OPERATOR_CANCELLED;
- if (BKE_object_obdata_is_libdata(ob)) {
- BKE_report(op->reports, RPT_ERROR, "Cannot apply pose to lib-linked armature"); /* error_libdata(); */
- return OPERATOR_CANCELLED;
- }
-
- /* helpful warnings... */
- /* TODO: add warnings to be careful about actions, applying deforms first, etc. */
- if (ob->adt && ob->adt->action)
- BKE_report(op->reports, RPT_WARNING,
- "Actions on this armature will be destroyed by this new rest pose as the "
- "transforms stored are relative to the old rest pose");
-
- /* Get editbones of active armature to alter */
- ED_armature_to_edit(ob);
-
- /* get pose of active object and move it out of posemode */
- pose = ob->pose;
-
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- curbone = editbone_name_exists(arm->edbo, pchan->name);
-
- /* simply copy the head/tail values from pchan over to curbone */
- copy_v3_v3(curbone->head, pchan->pose_head);
- copy_v3_v3(curbone->tail, pchan->pose_tail);
-
- /* fix roll:
- * 1. find auto-calculated roll value for this bone now
- * 2. remove this from the 'visual' y-rotation
- */
- {
- float premat[3][3], imat[3][3], pmat[3][3], tmat[3][3];
- float delta[3], eul[3];
-
- /* obtain new auto y-rotation */
- sub_v3_v3v3(delta, curbone->tail, curbone->head);
- vec_roll_to_mat3(delta, 0.0f, premat);
- invert_m3_m3(imat, premat);
-
- /* get pchan 'visual' matrix */
- copy_m3_m4(pmat, pchan->pose_mat);
-
- /* remove auto from visual and get euler rotation */
- mul_m3_m3m3(tmat, imat, pmat);
- mat3_to_eul(eul, tmat);
-
- /* just use this euler-y as new roll value */
- curbone->roll = eul[1];
- }
-
- /* clear transform values for pchan */
- zero_v3(pchan->loc);
- zero_v3(pchan->eul);
- unit_qt(pchan->quat);
- unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
- pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f;
-
- /* set anim lock */
- curbone->flag |= BONE_UNKEYED;
- }
-
- /* convert editbones back to bones, and then free the edit-data */
- ED_armature_from_edit(ob);
- ED_armature_edit_free(ob);
-
- /* flush positions of posebones */
- BKE_pose_where_is(scene, ob);
-
- /* fix parenting of objects which are bone-parented */
- applyarmature_fix_boneparents(scene, ob);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_armature_apply(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Apply Pose as Rest Pose";
- ot->idname = "POSE_OT_armature_apply";
- ot->description = "Apply the current pose as the new rest pose";
-
- /* callbacks */
- ot->exec = apply_armature_pose2bones_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-/* set the current pose as the restpose */
-static int pose_visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object
-
- /* don't check if editmode (should be done by caller) */
- if (ob->type != OB_ARMATURE)
- return OPERATOR_CANCELLED;
-
- /* loop over all selected pchans
- *
- * TODO, loop over children before parents if multiple bones
- * at once are to be predictable*/
- CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones)
- {
- float delta_mat[4][4];
-
- /* chan_mat already contains the delta transform from rest pose to pose-mode pose
- * as that is baked into there so that B-Bones will work. Once we've set this as the
- * new raw-transform components, don't recalc the poses yet, otherwise IK result will
- * change, thus changing the result we may be trying to record.
- */
- copy_m4_m4(delta_mat, pchan->chan_mat);
- BKE_pchan_apply_mat4(pchan, delta_mat, TRUE);
- }
- CTX_DATA_END;
-
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_visual_transform_apply(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Apply Visual Transform to Pose";
- ot->idname = "POSE_OT_visual_transform_apply";
- ot->description = "Apply final constrained position of pose bones to their transform";
-
- /* callbacks */
- ot->exec = pose_visual_transform_apply_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ---------------------- */
-
-/* Helper function for armature joining - link fixing */
-static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone)
-{
- Object *ob;
- bPose *pose;
- bPoseChannel *pchant;
- bConstraint *con;
-
- /* let's go through all objects in database */
- for (ob = G.main->object.first; ob; ob = ob->id.next) {
- /* do some object-type specific things */
- if (ob->type == OB_ARMATURE) {
- pose = ob->pose;
- for (pchant = pose->chanbase.first; pchant; pchant = pchant->next) {
- for (con = pchant->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == srcArm) {
- if (ct->subtarget[0] == '\0') {
- ct->tar = tarArm;
- }
- else if (strcmp(ct->subtarget, pchan->name) == 0) {
- ct->tar = tarArm;
- BLI_strncpy(ct->subtarget, curbone->name, sizeof(ct->subtarget));
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
-
- /* action constraint? */
- if (con->type == CONSTRAINT_TYPE_ACTION) {
- bActionConstraint *data = con->data; // XXX old animation system
- bAction *act;
- bActionChannel *achan;
-
- if (data->act) {
- act = data->act;
-
- for (achan = act->chanbase.first; achan; achan = achan->next) {
- if (strcmp(achan->name, pchan->name) == 0)
- BLI_strncpy(achan->name, curbone->name, sizeof(achan->name));
- }
- }
- }
-
- }
- }
- }
-
- /* fix object-level constraints */
- if (ob != srcArm) {
- for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == srcArm) {
- if (ct->subtarget[0] == '\0') {
- ct->tar = tarArm;
- }
- else if (strcmp(ct->subtarget, pchan->name) == 0) {
- ct->tar = tarArm;
- BLI_strncpy(ct->subtarget, curbone->name, sizeof(ct->subtarget));
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
-
- /* See if an object is parented to this armature */
- if (ob->parent && (ob->parent == srcArm)) {
- /* Is object parented to a bone of this src armature? */
- if (ob->partype == PARBONE) {
- /* bone name in object */
- if (!strcmp(ob->parsubstr, pchan->name))
- BLI_strncpy(ob->parsubstr, curbone->name, sizeof(ob->parsubstr));
- }
-
- /* make tar armature be new parent */
- ob->parent = tarArm;
- }
- }
-}
-
-/* join armature exec is exported for use in object->join objects operator... */
-int join_armature_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- bArmature *arm = (ob) ? ob->data : NULL;
- bPose *pose, *opose;
- bPoseChannel *pchan, *pchann;
- EditBone *curbone;
- float mat[4][4], oimat[4][4];
-
- /* Ensure we're not in editmode and that the active object is an armature*/
- if (!ob || ob->type != OB_ARMATURE)
- return OPERATOR_CANCELLED;
- if (!arm || arm->edbo)
- return OPERATOR_CANCELLED;
-
- /* Get editbones of active armature to add editbones to */
- ED_armature_to_edit(ob);
-
- /* get pose of active object and move it out of posemode */
- pose = ob->pose;
- ob->mode &= ~OB_MODE_POSE;
-
- CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases)
- {
- if ((base->object->type == OB_ARMATURE) && (base->object != ob)) {
- bArmature *curarm = base->object->data;
-
- /* Make a list of editbones in current armature */
- ED_armature_to_edit(base->object);
-
- /* Get Pose of current armature */
- opose = base->object->pose;
- base->object->mode &= ~OB_MODE_POSE;
- //BASACT->flag &= ~OB_MODE_POSE;
-
- /* Find the difference matrix */
- invert_m4_m4(oimat, ob->obmat);
- mult_m4_m4m4(mat, oimat, base->object->obmat);
-
- /* Copy bones and posechannels from the object to the edit armature */
- for (pchan = opose->chanbase.first; pchan; pchan = pchann) {
- pchann = pchan->next;
- curbone = editbone_name_exists(curarm->edbo, pchan->name);
-
- /* Get new name */
- unique_editbone_name(arm->edbo, curbone->name, NULL);
-
- /* Transform the bone */
- {
- float premat[4][4];
- float postmat[4][4];
- float difmat[4][4];
- float imat[4][4];
- float temp[3][3];
- float delta[3];
-
- /* Get the premat */
- sub_v3_v3v3(delta, curbone->tail, curbone->head);
- vec_roll_to_mat3(delta, curbone->roll, temp);
-
- unit_m4(premat); /* Mat4MulMat34 only sets 3x3 part */
- mul_m4_m3m4(premat, temp, mat);
-
- mul_m4_v3(mat, curbone->head);
- mul_m4_v3(mat, curbone->tail);
-
- /* Get the postmat */
- sub_v3_v3v3(delta, curbone->tail, curbone->head);
- vec_roll_to_mat3(delta, curbone->roll, temp);
- copy_m4_m3(postmat, temp);
-
- /* Find the roll */
- invert_m4_m4(imat, premat);
- mult_m4_m4m4(difmat, imat, postmat);
-
- curbone->roll -= (float)atan2(difmat[2][0], difmat[2][2]);
- }
-
- /* Fix Constraints and Other Links to this Bone and Armature */
- joined_armature_fix_links(ob, base->object, pchan, curbone);
-
- /* Rename pchan */
- BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name));
-
- /* Jump Ship! */
- BLI_remlink(curarm->edbo, curbone);
- BLI_addtail(arm->edbo, curbone);
-
- BLI_remlink(&opose->chanbase, pchan);
- BLI_addtail(&pose->chanbase, pchan);
- BKE_pose_channels_hash_free(opose);
- BKE_pose_channels_hash_free(pose);
- }
-
- ED_base_object_free_and_unlink(bmain, scene, base);
- }
- }
- CTX_DATA_END;
-
- DAG_relations_tag_update(bmain); /* because we removed object(s) */
-
- ED_armature_from_edit(ob);
- ED_armature_edit_free(ob);
-
- WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
-
- return OPERATOR_FINISHED;
-}
-
-/* ---------------------- */
-
-/* Helper function for armature separating - link fixing */
-static void separated_armature_fix_links(Object *origArm, Object *newArm)
-{
- Object *ob;
- bPoseChannel *pchan;
- bConstraint *con;
- ListBase *opchans, *npchans;
-
- /* get reference to list of bones in original and new armatures */
- opchans = &origArm->pose->chanbase;
- npchans = &newArm->pose->chanbase;
-
- /* let's go through all objects in database */
- for (ob = G.main->object.first; ob; ob = ob->id.next) {
- /* do some object-type specific things */
- if (ob->type == OB_ARMATURE) {
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- /* any targets which point to original armature are redirected to the new one only if:
- * - the target isn't origArm/newArm itself
- * - the target is one that can be found in newArm/origArm
- */
- if (ct->subtarget[0] != 0) {
- if (ct->tar == origArm) {
- if (BLI_findstring(npchans, ct->subtarget, offsetof(bPoseChannel, name))) {
- ct->tar = newArm;
- }
- }
- else if (ct->tar == newArm) {
- if (BLI_findstring(opchans, ct->subtarget, offsetof(bPoseChannel, name))) {
- ct->tar = origArm;
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
- }
- }
-
- /* fix object-level constraints */
- if (ob != origArm) {
- for (con = ob->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- /* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- /* any targets which point to original armature are redirected to the new one only if:
- * - the target isn't origArm/newArm itself
- * - the target is one that can be found in newArm/origArm
- */
- if (ct->subtarget[0] != '\0') {
- if (ct->tar == origArm) {
- if (BLI_findstring(npchans, ct->subtarget, offsetof(bPoseChannel, name))) {
- ct->tar = newArm;
- }
- }
- else if (ct->tar == newArm) {
- if (BLI_findstring(opchans, ct->subtarget, offsetof(bPoseChannel, name))) {
- ct->tar = origArm;
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
- }
-
- /* See if an object is parented to this armature */
- if (ob->parent && (ob->parent == origArm)) {
- /* Is object parented to a bone of this src armature? */
- if ((ob->partype == PARBONE) && (ob->parsubstr[0] != '\0')) {
- if (BLI_findstring(npchans, ob->parsubstr, offsetof(bPoseChannel, name))) {
- ob->parent = newArm;
- }
- }
- }
- }
-}
-
-/* Helper function for armature separating - remove certain bones from the given armature
- * sel: remove selected bones from the armature, otherwise the unselected bones are removed
- * (ob is not in editmode)
- */
-static void separate_armature_bones(Object *ob, short sel)
-{
- bArmature *arm = (bArmature *)ob->data;
- bPoseChannel *pchan, *pchann;
- EditBone *curbone;
-
- /* make local set of editbones to manipulate here */
- ED_armature_to_edit(ob);
-
- /* go through pose-channels, checking if a bone should be removed */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchann) {
- pchann = pchan->next;
- curbone = editbone_name_exists(arm->edbo, pchan->name);
-
- /* check if bone needs to be removed */
- if ( (sel && (curbone->flag & BONE_SELECTED)) ||
- (!sel && !(curbone->flag & BONE_SELECTED)) )
- {
- EditBone *ebo;
- bPoseChannel *pchn;
-
- /* clear the bone->parent var of any bone that had this as its parent */
- for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
- if (ebo->parent == curbone) {
- ebo->parent = NULL;
- ebo->temp = NULL; /* this is needed to prevent random crashes with in ED_armature_from_edit */
- ebo->flag &= ~BONE_CONNECTED;
- }
- }
-
- /* clear the pchan->parent var of any pchan that had this as its parent */
- for (pchn = ob->pose->chanbase.first; pchn; pchn = pchn->next) {
- if (pchn->parent == pchan)
- pchn->parent = NULL;
- }
-
- /* free any of the extra-data this pchan might have */
- BKE_pose_channel_free(pchan);
- BKE_pose_channels_hash_free(ob->pose);
-
- /* get rid of unneeded bone */
- bone_free(arm, curbone);
- BLI_freelinkN(&ob->pose->chanbase, pchan);
- }
- }
-
- /* exit editmode (recalculates pchans too) */
- ED_armature_from_edit(ob);
- ED_armature_edit_free(ob);
-}
-
-/* separate selected bones into their armature */
-static int separate_armature_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Object *obedit = CTX_data_edit_object(C);
- Object *oldob, *newob;
- Base *oldbase, *newbase;
-
- /* sanity checks */
- if (obedit == NULL)
- return OPERATOR_CANCELLED;
-
- /* set wait cursor in case this takes a while */
- WM_cursor_wait(1);
-
- /* we are going to do this as follows (unlike every other instance of separate):
- * 1. exit editmode +posemode for active armature/base. Take note of what this is.
- * 2. duplicate base - BASACT is the new one now
- * 3. for each of the two armatures, enter editmode -> remove appropriate bones -> exit editmode + recalc
- * 4. fix constraint links
- * 5. make original armature active and enter editmode
- */
-
- /* 1) only edit-base selected */
- /* TODO: use context iterators for this? */
- CTX_DATA_BEGIN(C, Base *, base, visible_bases)
- {
- if (base->object == obedit) base->flag |= 1;
- else base->flag &= ~1;
- }
- CTX_DATA_END;
-
- /* 1) store starting settings and exit editmode */
- oldob = obedit;
- oldbase = BASACT;
- oldob->mode &= ~OB_MODE_POSE;
- //oldbase->flag &= ~OB_POSEMODE;
-
- ED_armature_from_edit(obedit);
- ED_armature_edit_free(obedit);
-
- /* 2) duplicate base */
- newbase = ED_object_add_duplicate(bmain, scene, oldbase, USER_DUP_ARM); /* only duplicate linked armature */
- DAG_relations_tag_update(bmain);
-
- newob = newbase->object;
- newbase->flag &= ~SELECT;
-
-
- /* 3) remove bones that shouldn't still be around on both armatures */
- separate_armature_bones(oldob, 1);
- separate_armature_bones(newob, 0);
-
-
- /* 4) fix links before depsgraph flushes */ // err... or after?
- separated_armature_fix_links(oldob, newob);
-
- DAG_id_tag_update(&oldob->id, OB_RECALC_DATA); /* this is the original one */
- DAG_id_tag_update(&newob->id, OB_RECALC_DATA); /* this is the separated one */
-
-
- /* 5) restore original conditions */
- obedit = oldob;
-
- ED_armature_to_edit(obedit);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
-
- /* recalc/redraw + cleanup */
- WM_cursor_wait(0);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_separate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Separate Bones";
- ot->idname = "ARMATURE_OT_separate";
- ot->description = "Isolate selected bones into a separate armature";
-
- /* callbacks */
- ot->invoke = WM_operator_confirm;
- ot->exec = separate_armature_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* **************** END tools on Editmode Armature **************** */
-/* **************** PoseMode & EditMode *************************** */
-
-/* only for opengl selection indices */
-Bone *get_indexed_bone(Object *ob, int index)
-{
- bPoseChannel *pchan;
- if (ob->pose == NULL) return NULL;
- index >>= 16; // bone selection codes use left 2 bytes
-
- pchan = BLI_findlink(&ob->pose->chanbase, index);
- return pchan ? pchan->bone : NULL;
-}
-
-/* See if there are any selected bones in this buffer */
-/* only bones from base are checked on */
-static void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits, short findunsel)
-{
- Object *obedit = scene->obedit; // XXX get from context
- Bone *bone;
- EditBone *ebone;
- void *firstunSel = NULL, *firstSel = NULL, *data;
- unsigned int hitresult;
- short i, takeNext = 0, sel;
-
- for (i = 0; i < hits; i++) {
- hitresult = buffer[3 + (i * 4)];
-
- if (!(hitresult & BONESEL_NOSEL)) { // -1
- if (hitresult & BONESEL_ANY) { // to avoid including objects in selection
-
- hitresult &= ~(BONESEL_ANY);
- /* Determine what the current bone is */
- if (obedit == NULL || base->object != obedit) {
- /* no singular posemode, so check for correct object */
- if (base->selcol == (hitresult & 0xFFFF)) {
- bone = get_indexed_bone(base->object, hitresult);
-
- if (findunsel)
- sel = (bone->flag & BONE_SELECTED);
- else
- sel = !(bone->flag & BONE_SELECTED);
-
- data = bone;
- }
- else {
- data = NULL;
- sel = 0;
- }
- }
- else {
- bArmature *arm = obedit->data;
-
- ebone = BLI_findlink(arm->edbo, hitresult);
- if (findunsel)
- sel = (ebone->flag & BONE_SELECTED);
- else
- sel = !(ebone->flag & BONE_SELECTED);
-
- data = ebone;
- }
-
- if (data) {
- if (sel) {
- if (!firstSel) firstSel = data;
- takeNext = 1;
- }
- else {
- if (!firstunSel)
- firstunSel = data;
- if (takeNext)
- return data;
- }
- }
- }
- }
- }
-
- if (firstunSel)
- return firstunSel;
- else
- return firstSel;
-}
-
-
-
-/* used by posemode as well editmode */
-/* only checks scene->basact! */
-/* x and y are mouse coords (area space) */
-static void *get_nearest_bone(bContext *C, short findunsel, int x, int y)
-{
- ViewContext vc;
- rcti rect;
- unsigned int buffer[MAXPICKBUF];
- short hits;
-
- view3d_set_viewcontext(C, &vc);
-
- // rect.xmin = ... mouseco!
- rect.xmin = rect.xmax = x;
- rect.ymin = rect.ymax = y;
-
- glInitNames();
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
-
- if (hits > 0)
- return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel);
-
- return NULL;
-}
-
-/* Get the first available child of an editbone */
-static EditBone *editbone_get_child(bArmature *arm, EditBone *pabone, short use_visibility)
-{
- EditBone *curbone, *chbone = NULL;
-
- for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
- if (curbone->parent == pabone) {
- if (use_visibility) {
- if ((arm->layer & curbone->layer) && !(pabone->flag & BONE_HIDDEN_A)) {
- chbone = curbone;
- }
- }
- else
- chbone = curbone;
- }
- }
-
- return chbone;
-}
-
-/* **************** END PoseMode & EditMode *************************** */
-/* **************** Posemode stuff ********************** */
-
-
-static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
-{
- Bone *curBone;
-
- /* stop when unconnected child is encontered, or when unselectable bone is encountered */
- if (!(bone->flag & BONE_CONNECTED) || (bone->flag & BONE_UNSELECTABLE))
- return;
-
- /* XXX old cruft! use notifiers instead */
- //select_actionchannel_by_name (ob->action, bone->name, !(shift));
-
- if (extend)
- bone->flag &= ~BONE_SELECTED;
- else
- bone->flag |= BONE_SELECTED;
-
- for (curBone = bone->childbase.first; curBone; curBone = curBone->next)
- selectconnected_posebonechildren(ob, curBone, extend);
-}
-
-/* within active object context */
-/* previously known as "selectconnected_posearmature" */
-static int pose_select_connected_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (bArmature *)ob->data;
- Bone *bone, *curBone, *next = NULL;
- int extend = RNA_boolean_get(op->ptr, "extend");
-
- view3d_operator_needs_opengl(C);
-
- if (extend)
- bone = get_nearest_bone(C, 0, event->mval[0], event->mval[1]);
- else
- bone = get_nearest_bone(C, 1, event->mval[0], event->mval[1]);
-
- if (!bone)
- return OPERATOR_CANCELLED;
-
- /* Select parents */
- for (curBone = bone; curBone; curBone = next) {
- /* ignore bone if cannot be selected */
- if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
- // XXX old cruft! use notifiers instead
- //select_actionchannel_by_name (ob->action, curBone->name, !(shift));
-
- if (extend)
- curBone->flag &= ~BONE_SELECTED;
- else
- curBone->flag |= BONE_SELECTED;
-
- if (curBone->flag & BONE_CONNECTED)
- next = curBone->parent;
- else
- next = NULL;
- }
- else
- next = NULL;
- }
-
- /* Select children */
- for (curBone = bone->childbase.first; curBone; curBone = next)
- selectconnected_posebonechildren(ob, curBone, extend);
-
- /* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- return OPERATOR_FINISHED;
-}
-
-static int pose_select_linked_poll(bContext *C)
-{
- return (ED_operator_view3d_active(C) && ED_operator_posemode(C));
-}
-
-void POSE_OT_select_linked(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Connected";
- ot->idname = "POSE_OT_select_linked";
- ot->description = "Select bones related to selected ones by parent/child relationships";
-
- /* api callbacks */
- ot->exec = NULL;
- ot->invoke = pose_select_connected_invoke;
- ot->poll = pose_select_linked_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
-}
-
-/* **************** END Posemode stuff ********************** */
-/* **************** EditMode stuff ********************** */
-
-/* called in space.c */
-/* previously "selectconnected_armature" */
-static int armature_select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
- bArmature *arm;
- EditBone *bone, *curBone, *next;
- int extend = RNA_boolean_get(op->ptr, "extend");
- Object *obedit = CTX_data_edit_object(C);
- arm = obedit->data;
-
- view3d_operator_needs_opengl(C);
-
- if (extend)
- bone = get_nearest_bone(C, 0, event->mval[0], event->mval[1]);
- else
- bone = get_nearest_bone(C, 1, event->mval[0], event->mval[1]);
-
- if (!bone)
- return OPERATOR_CANCELLED;
-
- /* Select parents */
- for (curBone = bone; curBone; curBone = next) {
- if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
- if (extend) {
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
-
- if (curBone->flag & BONE_CONNECTED)
- next = curBone->parent;
- else
- next = NULL;
- }
-
- /* Select children */
- while (bone) {
- for (curBone = arm->edbo->first; curBone; curBone = next) {
- next = curBone->next;
- if ((curBone->parent == bone) && (curBone->flag & BONE_UNSELECTABLE) == 0) {
- if (curBone->flag & BONE_CONNECTED) {
- if (extend)
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- else
- curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- bone = curBone;
- break;
- }
- else {
- bone = NULL;
- break;
- }
- }
- }
- if (!curBone)
- bone = NULL;
- }
-
- ED_armature_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-static int armature_select_linked_poll(bContext *C)
-{
- return (ED_operator_view3d_active(C) && ED_operator_editarmature(C) );
-}
-
-void ARMATURE_OT_select_linked(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Connected";
- ot->idname = "ARMATURE_OT_select_linked";
- ot->description = "Select bones related to selected ones by parent/child relationships";
-
- /* api callbacks */
- ot->exec = NULL;
- ot->invoke = armature_select_linked_invoke;
- ot->poll = armature_select_linked_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
-}
-
-/* does bones and points */
-/* note that BONE ROOT only gets drawn for root bones (or without IK) */
-static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
- ListBase *edbo, int findunsel, int *selmask)
-{
- EditBone *ebone;
- rcti rect;
- unsigned int buffer[MAXPICKBUF];
- unsigned int hitresult, besthitresult = BONESEL_NOSEL;
- int i, mindep = 4;
- short hits;
-
- glInitNames();
-
- rect.xmin = mval[0] - 5;
- rect.xmax = mval[0] + 5;
- rect.ymin = mval[1] - 5;
- rect.ymax = mval[1] + 5;
-
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
- if (hits == 0) {
- rect.xmin = mval[0] - 12;
- rect.xmax = mval[0] + 12;
- rect.ymin = mval[1] - 12;
- rect.ymax = mval[1] + 12;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
- }
- /* See if there are any selected bones in this group */
- if (hits > 0) {
-
- if (hits == 1) {
- if (!(buffer[3] & BONESEL_NOSEL))
- besthitresult = buffer[3];
- }
- else {
- for (i = 0; i < hits; i++) {
- hitresult = buffer[3 + (i * 4)];
- if (!(hitresult & BONESEL_NOSEL)) {
- int dep;
-
- ebone = BLI_findlink(edbo, hitresult & ~BONESEL_ANY);
-
- /* clicks on bone points get advantage */
- if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
- /* but also the unselected one */
- if (findunsel) {
- if ( (hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0)
- dep = 1;
- else if ( (hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0)
- dep = 1;
- else
- dep = 2;
- }
- else dep = 2;
- }
- else {
- /* bone found */
- if (findunsel) {
- if ((ebone->flag & BONE_SELECTED) == 0)
- dep = 2;
- else
- dep = 3;
- }
- else dep = 3;
- }
- if (dep < mindep) {
- mindep = dep;
- besthitresult = hitresult;
- }
- }
- }
- }
-
- if (!(besthitresult & BONESEL_NOSEL)) {
-
- ebone = BLI_findlink(edbo, besthitresult & ~BONESEL_ANY);
-
- *selmask = 0;
- if (besthitresult & BONESEL_ROOT)
- *selmask |= BONE_ROOTSEL;
- if (besthitresult & BONESEL_TIP)
- *selmask |= BONE_TIPSEL;
- if (besthitresult & BONESEL_BONE)
- *selmask |= BONE_SELECTED;
- return ebone;
- }
- }
- *selmask = 0;
- return NULL;
-}
-
-/* previously delete_armature */
-/* only editmode! */
-static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
-{
- bArmature *arm;
- EditBone *curBone, *ebone_next;
- bConstraint *con;
- Object *obedit = CTX_data_edit_object(C); // XXX get from context
- arm = obedit->data;
-
- /* cancel if nothing selected */
- if (CTX_DATA_COUNT(C, selected_bones) == 0)
- return OPERATOR_CANCELLED;
-
- armature_select_mirrored(arm);
-
- /* First erase any associated pose channel */
- if (obedit->pose) {
- bPoseChannel *pchan, *pchan_next;
- for (pchan = obedit->pose->chanbase.first; pchan; pchan = pchan_next) {
- pchan_next = pchan->next;
- curBone = editbone_name_exists(arm->edbo, pchan->name);
-
- if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
- BKE_pose_channel_free(pchan);
- BKE_pose_channels_hash_free(obedit->pose);
- BLI_freelinkN(&obedit->pose->chanbase, pchan);
- }
- else {
- for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == obedit) {
- if (ct->subtarget[0]) {
- curBone = editbone_name_exists(arm->edbo, ct->subtarget);
- if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
- con->flag |= CONSTRAINT_DISABLE;
- ct->subtarget[0] = 0;
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 0);
- }
- }
- }
- }
- }
-
-
- for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
- ebone_next = curBone->next;
- if (arm->layer & curBone->layer) {
- if (curBone->flag & BONE_SELECTED) {
- if (curBone == arm->act_edbone) arm->act_edbone = NULL;
- ED_armature_edit_bone_remove(arm, curBone);
- }
- }
- }
-
-
- ED_armature_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_delete(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Delete Selected Bone(s)";
- ot->idname = "ARMATURE_OT_delete";
- ot->description = "Remove selected bones from the armature";
-
- /* api callbacks */
- ot->invoke = WM_operator_confirm;
- ot->exec = armature_delete_selected_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* toggle==0: deselect
- * toggle==1: swap (based on test)
- * toggle==2: swap (no test), CURRENTLY UNUSED
- */
-void ED_armature_deselect_all(Object *obedit, int toggle)
-{
- bArmature *arm = obedit->data;
- EditBone *eBone;
- int sel = 1;
-
- if (toggle == 1) {
- /* Determine if there are any selected bones
- * and therefore whether we are selecting or deselecting */
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- // if (arm->layer & eBone->layer) {
- if (eBone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
- sel = 0;
- break;
- }
- // }
- }
- }
- else sel = toggle;
-
- /* Set the flags */
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- if (sel == 2) {
- /* invert selection of bone */
- if (EBONE_VISIBLE(arm, eBone)) {
- eBone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (arm->act_edbone == eBone)
- arm->act_edbone = NULL;
- }
- }
- else if (sel == 1) {
- /* select bone */
- if (EBONE_VISIBLE(arm, eBone)) {
- eBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (eBone->parent)
- eBone->parent->flag |= (BONE_TIPSEL);
- }
- }
- else {
- /* deselect bone */
- eBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (arm->act_edbone == eBone)
- arm->act_edbone = NULL;
- }
- }
-
- ED_armature_sync_selection(arm->edbo);
-}
-
-void ED_armature_deselect_all_visible(Object *obedit)
-{
- bArmature *arm = obedit->data;
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- /* first and foremost, bone must be visible and selected */
- if (EBONE_SELECTABLE(arm, ebone)) {
- ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
-
- ED_armature_sync_selection(arm->edbo);
-}
-
-/* accounts for connected parents */
-static int ebone_select_flag(EditBone *ebone)
-{
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- return ((ebone->parent->flag & BONE_TIPSEL) ? BONE_ROOTSEL : 0) | (ebone->flag & (BONE_SELECTED | BONE_TIPSEL));
- }
- else {
- return ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
- }
-}
-
-/* context: editmode armature in view3d */
-int mouse_armature(bContext *C, const int mval[2], int extend, int deselect, int toggle)
-{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- ViewContext vc;
- EditBone *nearBone = NULL;
- int selmask;
-
- view3d_set_viewcontext(C, &vc);
-
- BIF_sk_selectStroke(C, mval, extend);
-
- nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, 1, &selmask);
- if (nearBone) {
-
- if (!extend && !deselect && !toggle)
- ED_armature_deselect_all(obedit, 0);
-
- /* by definition the non-root connected bones have no root point drawn,
- * so a root selection needs to be delivered to the parent tip */
-
- if (selmask & BONE_SELECTED) {
- if (nearBone->parent && (nearBone->flag & BONE_CONNECTED)) {
- /* click in a chain */
- if (extend) {
- /* select this bone */
- nearBone->flag |= BONE_TIPSEL;
- nearBone->parent->flag |= BONE_TIPSEL;
- }
- else if (deselect) {
- /* deselect this bone */
- nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
- /* only deselect parent tip if it is not selected */
- if (!(nearBone->parent->flag & BONE_SELECTED))
- nearBone->parent->flag &= ~BONE_TIPSEL;
- }
- else if (toggle) {
- /* hold shift inverts this bone's selection */
- if (nearBone->flag & BONE_SELECTED) {
- /* deselect this bone */
- nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
- /* only deselect parent tip if it is not selected */
- if (!(nearBone->parent->flag & BONE_SELECTED))
- nearBone->parent->flag &= ~BONE_TIPSEL;
- }
- else {
- /* select this bone */
- nearBone->flag |= BONE_TIPSEL;
- nearBone->parent->flag |= BONE_TIPSEL;
- }
- }
- else {
- /* select this bone */
- nearBone->flag |= BONE_TIPSEL;
- nearBone->parent->flag |= BONE_TIPSEL;
- }
- }
- else {
- if (extend) {
- nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if (deselect) {
- nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if (toggle) {
- /* hold shift inverts this bone's selection */
- if (nearBone->flag & BONE_SELECTED)
- nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
- else
- nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
- }
- else
- nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
- else {
- if (extend)
- nearBone->flag |= selmask;
- else if (deselect)
- nearBone->flag &= ~selmask;
- else if (toggle && (nearBone->flag & selmask))
- nearBone->flag &= ~selmask;
- else
- nearBone->flag |= selmask;
- }
-
- ED_armature_sync_selection(arm->edbo);
-
- if (nearBone) {
- /* then now check for active status */
- if (ebone_select_flag(nearBone)) {
- arm->act_edbone = nearBone;
- }
- }
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
- return 1;
- }
-
- return 0;
-}
-
-void ED_armature_edit_free(struct Object *ob)
-{
- bArmature *arm = ob->data;
- EditBone *eBone;
-
- /* Clear the editbones list */
- if (arm->edbo) {
- if (arm->edbo->first) {
- for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
- if (eBone->prop) {
- IDP_FreeProperty(eBone->prop);
- MEM_freeN(eBone->prop);
- }
- }
-
- BLI_freelistN(arm->edbo);
- }
- MEM_freeN(arm->edbo);
- arm->edbo = NULL;
- }
-}
-
-/* Put armature in EditMode */
-void ED_armature_to_edit(Object *ob)
-{
- bArmature *arm = ob->data;
-
- ED_armature_edit_free(ob);
- arm->edbo = MEM_callocN(sizeof(ListBase), "edbo armature");
- arm->act_edbone = make_boneList(arm->edbo, &arm->bonebase, NULL, arm->act_bone);
- arm->act_bone = NULL;
-
-// BIF_freeTemplates(); /* force template update when entering editmode */
-}
-
-
-/* adjust bone roll to align Z axis with vector
- * vec is in local space and is normalized
- */
-
-float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const short axis_only)
-{
- float mat[3][3], nor[3];
-
- sub_v3_v3v3(nor, bone->tail, bone->head);
- vec_roll_to_mat3(nor, 0.0f, mat);
-
- /* check the bone isn't aligned with the axis */
- if (!is_zero_v3(align_axis) && angle_v3v3(align_axis, mat[2]) > FLT_EPSILON) {
- float vec[3], align_axis_proj[3], roll;
-
- /* project the new_up_axis along the normal */
- project_v3_v3v3(vec, align_axis, nor);
- sub_v3_v3v3(align_axis_proj, align_axis, vec);
-
- if (axis_only) {
- if (angle_v3v3(align_axis_proj, mat[2]) > (float)(M_PI / 2.0)) {
- negate_v3(align_axis_proj);
- }
- }
-
- roll = angle_v3v3(align_axis_proj, mat[2]);
-
- cross_v3_v3v3(vec, mat[2], align_axis_proj);
-
- if (dot_v3v3(vec, nor) < 0) {
- roll = -roll;
- }
-
- return roll;
- }
-
- return 0.0f;
-}
-
-
-static EnumPropertyItem prop_calc_roll_types[] = {
- {0, "X", 0, "X Axis", ""},
- {1, "Y", 0, "Y Axis", ""},
- {2, "Z", 0, "Z Axis", ""},
- {5, "ACTIVE", 0, "Active Bone", ""},
- {6, "VIEW", 0, "View Axis", ""},
- {7, "CURSOR", 0, "Cursor", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-
-static int armature_calc_roll_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_edit_object(C);
- const short type = RNA_enum_get(op->ptr, "type");
- const short axis_only = RNA_boolean_get(op->ptr, "axis_only");
- const short axis_flip = RNA_boolean_get(op->ptr, "axis_flip");
-
- float imat[3][3];
-
- bArmature *arm = ob->data;
- EditBone *ebone;
-
- copy_m3_m4(imat, ob->obmat);
- invert_m3(imat);
-
- if (type == 7) { /* Cursor */
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C); /* can be NULL */
- float cursor_local[3];
- const float *cursor = give_cursor(scene, v3d);
-
-
- copy_v3_v3(cursor_local, cursor);
- mul_m3_v3(imat, cursor_local);
-
- /* cursor */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
- float cursor_rel[3];
- sub_v3_v3v3(cursor_rel, cursor_local, ebone->head);
- if (axis_flip) negate_v3(cursor_rel);
- ebone->roll = ED_rollBoneToVector(ebone, cursor_rel, axis_only);
- }
- }
- }
- else {
- float vec[3] = {0.0f, 0.0f, 0.0f};
- if (type == 6) { /* View */
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- if (rv3d == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No region view3d available");
- return OPERATOR_CANCELLED;
- }
-
- copy_v3_v3(vec, rv3d->viewinv[2]);
- mul_m3_v3(imat, vec);
- }
- else if (type == 5) {
- float mat[3][3], nor[3];
- ebone = (EditBone *)arm->act_edbone;
- if (ebone == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active bone set");
- return OPERATOR_CANCELLED;
- }
-
- sub_v3_v3v3(nor, ebone->tail, ebone->head);
- vec_roll_to_mat3(nor, ebone->roll, mat);
- copy_v3_v3(vec, mat[2]);
- }
- else { /* Axis */
- assert(type >= 0 && type <= 5);
- if (type < 3) vec[type] = 1.0f;
- else vec[type - 2] = -1.0f;
- mul_m3_v3(imat, vec);
- }
-
- if (axis_flip) negate_v3(vec);
-
- 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 = ED_rollBoneToVector(ebone, vec, axis_only);
- }
- }
- }
-
- 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_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_calculate_roll(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Recalculate Roll";
- ot->idname = "ARMATURE_OT_calculate_roll";
- ot->description = "Automatically fix alignment of select bones' axes";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_calc_roll_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, 0, "Type", "");
- RNA_def_boolean(ot->srna, "axis_flip", 0, "Flip Axis", "Negate the alignment axis");
- RNA_def_boolean(ot->srna, "axis_only", 0, "Shortest Rotation", "Ignore the axis direction, use the shortest rotation to align");
-}
-
-/* **************** undo for armatures ************** */
-
-typedef struct UndoArmature {
- EditBone *act_edbone;
- ListBase lb;
-} UndoArmature;
-
-static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data))
-{
- UndoArmature *uarm = uarmv;
- bArmature *arm = armv;
- EditBone *ebo, *newebo;
-
- BLI_freelistN(arm->edbo);
-
- /* copy */
- for (ebo = uarm->lb.first; ebo; ebo = ebo->next) {
- newebo = MEM_dupallocN(ebo);
- ebo->temp = newebo;
- BLI_addtail(arm->edbo, newebo);
- }
-
- /* active bone */
- if (uarm->act_edbone) {
- ebo = uarm->act_edbone;
- arm->act_edbone = ebo->temp;
- }
- else
- arm->act_edbone = NULL;
-
- /* set pointers */
- for (newebo = arm->edbo->first; newebo; newebo = newebo->next) {
- if (newebo->parent) newebo->parent = newebo->parent->temp;
- }
- /* be sure they don't hang ever */
- for (newebo = arm->edbo->first; newebo; newebo = newebo->next) {
- newebo->temp = NULL;
- }
-}
-
-static void *editBones_to_undoBones(void *armv, void *UNUSED(obdata))
-{
- bArmature *arm = armv;
- UndoArmature *uarm;
- EditBone *ebo, *newebo;
-
- uarm = MEM_callocN(sizeof(UndoArmature), "listbase undo");
-
- /* copy */
- for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
- newebo = MEM_dupallocN(ebo);
- ebo->temp = newebo;
- BLI_addtail(&uarm->lb, newebo);
- }
-
- /* active bone */
- if (arm->act_edbone) {
- ebo = arm->act_edbone;
- uarm->act_edbone = ebo->temp;
- }
-
- /* set pointers */
- for (newebo = uarm->lb.first; newebo; newebo = newebo->next) {
- if (newebo->parent) newebo->parent = newebo->parent->temp;
- }
-
- return uarm;
-}
-
-static void free_undoBones(void *uarmv)
-{
- UndoArmature *uarm = uarmv;
-
- BLI_freelistN(&uarm->lb);
- MEM_freeN(uarm);
-}
-
-static void *get_armature_edit(bContext *C)
-{
- Object *obedit = CTX_data_edit_object(C);
- if (obedit && obedit->type == OB_ARMATURE) {
- return obedit->data;
- }
- return NULL;
-}
-
-/* and this is all the undo system needs to know */
-void undo_push_armature(bContext *C, const char *name)
-{
- // XXX solve getdata()
- undo_editmode_push(C, name, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL);
-}
-
-
-
-/* **************** END EditMode stuff ********************** */
-/* *************** Adding stuff in editmode *************** */
-
-/* default bone add, returns it selected, but without tail set */
-/* XXX should be used everywhere, now it mallocs bones still locally in functions */
-EditBone *ED_armature_edit_bone_add(bArmature *arm, const char *name)
-{
- EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone");
-
- BLI_strncpy(bone->name, name, sizeof(bone->name));
- unique_editbone_name(arm->edbo, bone->name, NULL);
-
- BLI_addtail(arm->edbo, bone);
-
- bone->flag |= BONE_TIPSEL;
- bone->weight = 1.0f;
- bone->dist = 0.25f;
- bone->xwidth = 0.1f;
- bone->zwidth = 0.1f;
- bone->ease1 = 1.0f;
- bone->ease2 = 1.0f;
- bone->rad_head = 0.10f;
- bone->rad_tail = 0.05f;
- bone->segments = 1;
- bone->layer = arm->layer;
-
- return bone;
-}
-
-/* v3d and rv3d are allowed to be NULL */
-void add_primitive_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d)
-{
- Object *obedit = scene->obedit; // XXX get from context
- bArmature *arm = obedit->data;
- float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
- EditBone *bone;
-
- /* Get inverse point for head and orientation for tail */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d));
-
- if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
- copy_m3_m4(obmat, rv3d->viewmat);
- else unit_m3(obmat);
-
- copy_m3_m4(viewmat, obedit->obmat);
- mul_m3_m3m3(totmat, obmat, viewmat);
- invert_m3_m3(imat, totmat);
-
- ED_armature_deselect_all(obedit, 0);
-
- /* Create a bone */
- bone = ED_armature_edit_bone_add(arm, "Bone");
-
- arm->act_edbone = bone;
-
- copy_v3_v3(bone->head, curs);
-
- if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
- add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1
- else
- add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z
-}
-
-
-/* previously addvert_armature */
-/* the ctrl-click method */
-static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op))
-{
- View3D *v3d;
- bArmature *arm;
- EditBone *ebone, *newbone, *flipbone;
- float mat[3][3], imat[3][3];
- const float *curs;
- int a, to_root = 0;
- Object *obedit;
- Scene *scene;
-
- scene = CTX_data_scene(C);
- v3d = CTX_wm_view3d(C);
- obedit = CTX_data_edit_object(C);
- arm = obedit->data;
-
- /* find the active or selected bone */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & BONE_TIPSEL || arm->act_edbone == ebone)
- break;
- }
- }
-
- if (ebone == NULL) {
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & BONE_ROOTSEL || arm->act_edbone == ebone)
- break;
- }
- }
- if (ebone == NULL)
- return OPERATOR_CANCELLED;
-
- to_root = 1;
- }
-
- ED_armature_deselect_all(obedit, 0);
-
- /* we re-use code for mirror editing... */
- flipbone = NULL;
- if (arm->flag & ARM_MIRROR_EDIT)
- flipbone = ED_armature_bone_get_mirrored(arm->edbo, ebone);
-
- for (a = 0; a < 2; a++) {
- if (a == 1) {
- if (flipbone == NULL)
- break;
- else {
- SWAP(EditBone *, flipbone, ebone);
- }
- }
-
- newbone = ED_armature_edit_bone_add(arm, ebone->name);
- arm->act_edbone = newbone;
-
- if (to_root) {
- copy_v3_v3(newbone->head, ebone->head);
- newbone->rad_head = ebone->rad_tail;
- newbone->parent = ebone->parent;
- }
- else {
- copy_v3_v3(newbone->head, ebone->tail);
- newbone->rad_head = ebone->rad_tail;
- newbone->parent = ebone;
- newbone->flag |= BONE_CONNECTED;
- }
-
- curs = give_cursor(scene, v3d);
- copy_v3_v3(newbone->tail, curs);
- sub_v3_v3v3(newbone->tail, newbone->tail, obedit->obmat[3]);
-
- if (a == 1)
- newbone->tail[0] = -newbone->tail[0];
-
- copy_m3_m4(mat, obedit->obmat);
- invert_m3_m3(imat, mat);
- mul_m3_v3(imat, newbone->tail);
-
- newbone->length = len_v3v3(newbone->head, newbone->tail);
- newbone->rad_tail = newbone->length * 0.05f;
- newbone->dist = newbone->length * 0.25f;
-
- }
-
- ED_armature_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-static int armature_click_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
- /* TODO most of this code is copied from set3dcursor_invoke,
- * it would be better to reuse code in set3dcursor_invoke */
-
- /* temporarily change 3d cursor position */
- Scene *scene;
- ARegion *ar;
- View3D *v3d;
- float *fp, tvec[3], oldcurs[3], mval_f[2];
- int retv;
-
- scene = CTX_data_scene(C);
- ar = CTX_wm_region(C);
- v3d = CTX_wm_view3d(C);
-
- fp = give_cursor(scene, v3d);
-
- copy_v3_v3(oldcurs, fp);
-
- VECCOPY2D(mval_f, event->mval);
- ED_view3d_win_to_3d(ar, fp, mval_f, tvec);
- copy_v3_v3(fp, tvec);
-
- /* extrude to the where new cursor is and store the operation result */
- retv = armature_click_extrude_exec(C, op);
-
- /* restore previous 3d cursor position */
- copy_v3_v3(fp, oldcurs);
-
- return retv;
-}
-
-void ARMATURE_OT_click_extrude(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Click-Extrude";
- ot->idname = "ARMATURE_OT_click_extrude";
- ot->description = "Create a new bone going from the last selected joint to the mouse position";
-
- /* api callbacks */
- ot->invoke = armature_click_extrude_invoke;
- ot->exec = armature_click_extrude_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
-}
-
-/* adds an EditBone between the nominated locations (should be in the right space) */
-static EditBone *add_points_bone(Object *obedit, float head[], float tail[])
-{
- EditBone *ebo;
-
- ebo = ED_armature_edit_bone_add(obedit->data, "Bone");
-
- copy_v3_v3(ebo->head, head);
- copy_v3_v3(ebo->tail, tail);
-
- return ebo;
-}
-
-
-static EditBone *get_named_editbone(ListBase *edbo, char *name)
-{
- EditBone *eBone;
-
- if (name) {
- for (eBone = edbo->first; eBone; eBone = eBone->next) {
- if (!strcmp(name, eBone->name))
- return eBone;
- }
- }
-
- return NULL;
-}
-
-/* Call this before doing any duplications
- * */
-void preEditBoneDuplicate(ListBase *editbones)
-{
- EditBone *eBone;
-
- /* clear temp */
- for (eBone = editbones->first; eBone; eBone = eBone->next) {
- eBone->temp = NULL;
- }
-}
-
-/*
- * Note: When duplicating cross objects, editbones here is the list of bones
- * from the SOURCE object but ob is the DESTINATION object
- * */
-void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Object *src_ob, Object *dst_ob)
-{
- /* If an edit bone has been duplicated, lets
- * update it's constraints if the subtarget
- * they point to has also been duplicated
- */
- EditBone *oldtarget, *newtarget;
- bPoseChannel *pchan;
- bConstraint *curcon;
- ListBase *conlist;
-
- if ( (pchan = BKE_pose_channel_verify(dst_ob->pose, dupBone->name)) ) {
- if ( (conlist = &pchan->constraints) ) {
- for (curcon = conlist->first; curcon; curcon = curcon->next) {
- /* does this constraint have a subtarget in
- * this armature?
- */
- bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if ((ct->tar == src_ob) && (ct->subtarget[0])) {
- ct->tar = dst_ob; /* update target */
- oldtarget = get_named_editbone(editbones, ct->subtarget);
- if (oldtarget) {
- /* was the subtarget bone duplicated too? If
- * so, update the constraint to point at the
- * duplicate of the old subtarget.
- */
- if (oldtarget->temp) {
- newtarget = (EditBone *) oldtarget->temp;
- BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
- }
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
- }
- }
- }
-}
-
-void updateDuplicateSubtarget(EditBone *dupBone, ListBase *editbones, Object *ob)
-{
- updateDuplicateSubtargetObjects(dupBone, editbones, ob, ob);
-}
-
-
-EditBone *duplicateEditBoneObjects(EditBone *curBone, const char *name, ListBase *editbones,
- Object *src_ob, Object *dst_ob)
-{
- EditBone *eBone = MEM_mallocN(sizeof(EditBone), "addup_editbone");
-
- /* Copy data from old bone to new bone */
- memcpy(eBone, curBone, sizeof(EditBone));
-
- curBone->temp = eBone;
- eBone->temp = curBone;
-
- if (name != NULL) {
- BLI_strncpy(eBone->name, name, sizeof(eBone->name));
- }
-
- unique_editbone_name(editbones, eBone->name, NULL);
- BLI_addtail(editbones, eBone);
-
- /* copy the ID property */
- if (curBone->prop)
- eBone->prop = IDP_CopyProperty(curBone->prop);
-
- /* Lets duplicate the list of constraints that the
- * current bone has.
- */
- if (src_ob->pose) {
- bPoseChannel *chanold, *channew;
-
- chanold = BKE_pose_channel_verify(src_ob->pose, curBone->name);
- if (chanold) {
- /* WARNING: this creates a new posechannel, but there will not be an attached bone
- * yet as the new bones created here are still 'EditBones' not 'Bones'.
- */
- channew = BKE_pose_channel_verify(dst_ob->pose, eBone->name);
-
- if (channew) {
- BKE_pose_channel_copy_data(channew, chanold);
- }
- }
- }
-
- return eBone;
-}
-
-EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editbones, Object *ob)
-{
- return duplicateEditBoneObjects(curBone, name, editbones, ob, ob);
-}
-
-/* previously adduplicate_armature */
-static int armature_duplicate_selected_exec(bContext *C, wmOperator *UNUSED(op))
-{
- bArmature *arm;
- EditBone *eBone = NULL;
- EditBone *curBone;
- EditBone *firstDup = NULL; /* The beginning of the duplicated bones in the edbo list */
-
- Object *obedit = CTX_data_edit_object(C);
- arm = obedit->data;
-
- /* cancel if nothing selected */
- if (CTX_DATA_COUNT(C, selected_bones) == 0)
- return OPERATOR_CANCELLED;
-
- ED_armature_sync_selection(arm->edbo); // XXX why is this needed?
-
- preEditBoneDuplicate(arm->edbo);
-
- /* Select mirrored bones */
- if (arm->flag & ARM_MIRROR_EDIT) {
- for (curBone = arm->edbo->first; curBone; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
- eBone = ED_armature_bone_get_mirrored(arm->edbo, curBone);
- if (eBone)
- eBone->flag |= BONE_SELECTED;
- }
- }
- }
- }
-
-
- /* Find the selected bones and duplicate them as needed */
- for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
-
- eBone = duplicateEditBone(curBone, curBone->name, arm->edbo, obedit);
-
- if (!firstDup)
- firstDup = eBone;
-
- }
- }
- }
-
- /* Run though the list and fix the pointers */
- for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone)) {
- if (curBone->flag & BONE_SELECTED) {
- eBone = (EditBone *) curBone->temp;
-
- if (!curBone->parent) {
- /* If this bone has no parent,
- * Set the duplicate->parent to NULL
- */
- eBone->parent = NULL;
- }
- else if (curBone->parent->temp) {
- /* If this bone has a parent that was duplicated,
- * Set the duplicate->parent to the curBone->parent->temp
- */
- eBone->parent = (EditBone *)curBone->parent->temp;
- }
- else {
- /* If this bone has a parent that IS not selected,
- * Set the duplicate->parent to the curBone->parent
- */
- eBone->parent = (EditBone *) curBone->parent;
- eBone->flag &= ~BONE_CONNECTED;
- }
-
- /* Lets try to fix any constraint subtargets that might
- * have been duplicated
- */
- updateDuplicateSubtarget(eBone, arm->edbo, obedit);
- }
- }
- }
-
- /* correct the active bone */
- if (arm->act_edbone) {
- eBone = arm->act_edbone;
- if (eBone->temp)
- arm->act_edbone = eBone->temp;
- }
-
- /* Deselect the old bones and select the new ones */
- for (curBone = arm->edbo->first; curBone && curBone != firstDup; curBone = curBone->next) {
- if (EBONE_VISIBLE(arm, curBone))
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
-
- ED_armature_validate_active(arm);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-
-void ARMATURE_OT_duplicate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Duplicate Selected Bone(s)";
- ot->idname = "ARMATURE_OT_duplicate";
- ot->description = "Make copies of the selected bones within the same armature";
-
- /* api callbacks */
- ot->exec = armature_duplicate_selected_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-/* *************** END Adding stuff in editmode *************** */
-/* ************** Add/Remove stuff in editmode **************** */
-
-/* temporary data-structure for merge/fill bones */
-typedef struct EditBonePoint {
- struct EditBonePoint *next, *prev;
-
- EditBone *head_owner; /* EditBone which uses this point as a 'head' point */
- EditBone *tail_owner; /* EditBone which uses this point as a 'tail' point */
-
- float vec[3]; /* the actual location of the point in local/EditMode space */
-} EditBonePoint;
-
-/* find chain-tips (i.e. bones without children) */
-static void chains_find_tips(ListBase *edbo, ListBase *list)
-{
- EditBone *curBone, *ebo;
- LinkData *ld;
-
- /* note: this is potentially very slow ... there's got to be a better way */
- for (curBone = edbo->first; curBone; curBone = curBone->next) {
- short stop = 0;
-
- /* is this bone contained within any existing chain? (skip if so) */
- for (ld = list->first; ld; ld = ld->next) {
- for (ebo = ld->data; ebo; ebo = ebo->parent) {
- if (ebo == curBone) {
- stop = 1;
- break;
- }
- }
-
- if (stop) break;
- }
- /* skip current bone if it is part of an existing chain */
- if (stop) continue;
-
- /* is any existing chain part of the chain formed by this bone? */
- stop = 0;
- for (ebo = curBone->parent; ebo; ebo = ebo->parent) {
- for (ld = list->first; ld; ld = ld->next) {
- if (ld->data == ebo) {
- ld->data = curBone;
- stop = 1;
- break;
- }
- }
-
- if (stop) break;
- }
- /* current bone has already been added to a chain? */
- if (stop) continue;
-
- /* add current bone to a new chain */
- ld = MEM_callocN(sizeof(LinkData), "BoneChain");
- ld->data = curBone;
- BLI_addtail(list, ld);
- }
-}
-
-/* --------------------- */
-
-static void fill_add_joint(EditBone *ebo, short eb_tail, ListBase *points)
-{
- EditBonePoint *ebp;
- float vec[3];
- short found = 0;
-
- if (eb_tail) {
- copy_v3_v3(vec, ebo->tail);
- }
- else {
- copy_v3_v3(vec, ebo->head);
- }
-
- for (ebp = points->first; ebp; ebp = ebp->next) {
- if (equals_v3v3(ebp->vec, vec)) {
- if (eb_tail) {
- if ((ebp->head_owner) && (ebp->head_owner->parent == ebo)) {
- /* so this bone's tail owner is this bone */
- ebp->tail_owner = ebo;
- found = 1;
- break;
- }
- }
- else {
- if ((ebp->tail_owner) && (ebo->parent == ebp->tail_owner)) {
- /* so this bone's head owner is this bone */
- ebp->head_owner = ebo;
- found = 1;
- break;
- }
- }
- }
- }
-
- /* allocate a new point if no existing point was related */
- if (found == 0) {
- ebp = MEM_callocN(sizeof(EditBonePoint), "EditBonePoint");
-
- if (eb_tail) {
- copy_v3_v3(ebp->vec, ebo->tail);
- ebp->tail_owner = ebo;
- }
- else {
- copy_v3_v3(ebp->vec, ebo->head);
- ebp->head_owner = ebo;
- }
-
- BLI_addtail(points, ebp);
- }
-}
-
-/* bone adding between selected joints */
-static int armature_fill_bones_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = (obedit) ? obedit->data : NULL;
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- ListBase points = {NULL, NULL};
- int count;
-
- /* sanity checks */
- if (ELEM(NULL, obedit, arm))
- return OPERATOR_CANCELLED;
-
- /* loop over all bones, and only consider if visible */
- CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
- {
- if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL))
- fill_add_joint(ebone, 0, &points);
- if (ebone->flag & BONE_TIPSEL)
- fill_add_joint(ebone, 1, &points);
- }
- CTX_DATA_END;
-
- /* the number of joints determines how we fill:
- * 1) between joint and cursor (joint=head, cursor=tail)
- * 2) between the two joints (order is dependent on active-bone/hierachy)
- * 3+) error (a smarter method involving finding chains needs to be worked out
- */
- count = BLI_countlist(&points);
-
- if (count == 0) {
- BKE_report(op->reports, RPT_ERROR, "No joints selected");
- return OPERATOR_CANCELLED;
- }
- else if (count == 1) {
- EditBonePoint *ebp;
- float curs[3];
-
- /* Get Points - selected joint */
- ebp = (EditBonePoint *)points.first;
-
- /* Get points - cursor (tail) */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d));
-
- /* Create a bone */
- /* newbone = */ add_points_bone(obedit, ebp->vec, curs);
- }
- else if (count == 2) {
- EditBonePoint *ebp, *ebp2;
- float head[3], tail[3];
- short headtail = 0;
-
- /* check that the points don't belong to the same bone */
- ebp = (EditBonePoint *)points.first;
- ebp2 = ebp->next;
-
- if ((ebp->head_owner == ebp2->tail_owner) && (ebp->head_owner != NULL)) {
- BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
- BLI_freelistN(&points);
- return OPERATOR_CANCELLED;
- }
- if ((ebp->tail_owner == ebp2->head_owner) && (ebp->tail_owner != NULL)) {
- BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
- BLI_freelistN(&points);
- return OPERATOR_CANCELLED;
- }
-
- /* find which one should be the 'head' */
- if ((ebp->head_owner && ebp2->head_owner) || (ebp->tail_owner && ebp2->tail_owner)) {
- /* rule: whichever one is closer to 3d-cursor */
- float curs[3];
- float vecA[3], vecB[3];
- float distA, distB;
-
- /* get cursor location */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d));
-
- /* get distances */
- sub_v3_v3v3(vecA, ebp->vec, curs);
- sub_v3_v3v3(vecB, ebp2->vec, curs);
- distA = len_v3(vecA);
- distB = len_v3(vecB);
-
- /* compare distances - closer one therefore acts as direction for bone to go */
- headtail = (distA < distB) ? 2 : 1;
- }
- else if (ebp->head_owner) {
- headtail = 1;
- }
- else if (ebp2->head_owner) {
- headtail = 2;
- }
-
- /* assign head/tail combinations */
- if (headtail == 2) {
- copy_v3_v3(head, ebp->vec);
- copy_v3_v3(tail, ebp2->vec);
- }
- else if (headtail == 1) {
- copy_v3_v3(head, ebp2->vec);
- copy_v3_v3(tail, ebp->vec);
- }
-
- /* add new bone and parent it to the appropriate end */
- if (headtail) {
- EditBone *newbone = add_points_bone(obedit, head, tail);
-
- /* do parenting (will need to set connected flag too) */
- if (headtail == 2) {
- /* ebp tail or head - tail gets priority */
- if (ebp->tail_owner)
- newbone->parent = ebp->tail_owner;
- else
- newbone->parent = ebp->head_owner;
- }
- else {
- /* ebp2 tail or head - tail gets priority */
- if (ebp2->tail_owner)
- newbone->parent = ebp2->tail_owner;
- else
- newbone->parent = ebp2->head_owner;
- }
-
- newbone->flag |= BONE_CONNECTED;
- }
- }
- else {
- /* FIXME.. figure out a method for multiple bones */
- BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count);
- BLI_freelistN(&points);
- return OPERATOR_CANCELLED;
- }
-
- /* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
-
- /* free points */
- BLI_freelistN(&points);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_fill(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Fill Between Joints";
- ot->idname = "ARMATURE_OT_fill";
- ot->description = "Add bone between selected joint(s) and/or 3D-Cursor";
-
- /* callbacks */
- ot->exec = armature_fill_bones_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* --------------------- */
-
-/* this function merges between two bones, removes them and those in-between,
- * and adjusts the parent relationships for those in-between
- */
-static void bones_merge(Object *obedit, EditBone *start, EditBone *end, EditBone *endchild, ListBase *chains)
-{
- bArmature *arm = obedit->data;
- EditBone *ebo, *ebone, *newbone;
- LinkData *chain;
- float head[3], tail[3];
-
- /* check if same bone */
- if (start == end) {
- if (G.debug & G_DEBUG) {
- printf("Error: same bone!\n");
- printf("\tstart = %s, end = %s\n", start->name, end->name);
- }
- }
-
- /* step 1: add a new bone
- * - head = head/tail of start (default head)
- * - tail = head/tail of end (default tail)
- * - parent = parent of start
- */
- if ((start->flag & BONE_TIPSEL) && (start->flag & BONE_SELECTED) == 0) {
- copy_v3_v3(head, start->tail);
- }
- else {
- copy_v3_v3(head, start->head);
- }
- if ((end->flag & BONE_ROOTSEL) && (end->flag & BONE_SELECTED) == 0) {
- copy_v3_v3(tail, end->head);
- }
- else {
- copy_v3_v3(tail, end->tail);
- }
- newbone = add_points_bone(obedit, head, tail);
- newbone->parent = start->parent;
-
- /* TODO, copy more things to the new bone */
- newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_SCALE |
- BONE_NO_CYCLICOFFSET | BONE_NO_LOCAL_LOCATION | BONE_DONE);
-
- /* step 2a: reparent any side chains which may be parented to any bone in the chain of bones to merge
- * - potentially several tips for side chains leading to some tree exist...
- */
- for (chain = chains->first; chain; chain = chain->next) {
- /* traverse down chain until we hit the bottom or if we run into the tip of the chain of bones we're
- * merging (need to stop in this case to avoid corrupting this chain too!)
- */
- for (ebone = chain->data; (ebone) && (ebone != end); ebone = ebone->parent) {
- short found = 0;
-
- /* check if this bone is parented to one in the merging chain
- * ! WATCHIT: must only go check until end of checking chain
- */
- for (ebo = end; (ebo) && (ebo != start->parent); ebo = ebo->parent) {
- /* side-chain found? --> remap parent to new bone, then we're done with this chain :) */
- if (ebone->parent == ebo) {
- ebone->parent = newbone;
- found = 1;
- break;
- }
- }
-
- /* carry on to the next tip now */
- if (found)
- break;
- }
- }
-
- /* step 2b: parent child of end to newbone (child from this chain) */
- if (endchild)
- endchild->parent = newbone;
-
- /* step 3: delete all bones between and including start and end */
- for (ebo = end; ebo; ebo = ebone) {
- ebone = (ebo == start) ? (NULL) : (ebo->parent);
- bone_free(arm, ebo);
- }
-
- newbone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED);
- ED_armature_sync_selection(arm->edbo);
-}
-
-
-static int armature_merge_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = (obedit) ? obedit->data : NULL;
- short type = RNA_enum_get(op->ptr, "type");
-
- /* sanity checks */
- if (ELEM(NULL, obedit, arm))
- return OPERATOR_CANCELLED;
-
- /* for now, there's only really one type of merging that's performed... */
- if (type == 1) {
- /* go down chains, merging bones */
- ListBase chains = {NULL, NULL};
- LinkData *chain, *nchain;
- EditBone *ebo;
-
- armature_tag_select_mirrored(arm);
-
- /* get chains (ends on chains) */
- chains_find_tips(arm->edbo, &chains);
- if (chains.first == NULL) return OPERATOR_CANCELLED;
-
- /* each 'chain' is the last bone in the chain (with no children) */
- for (chain = chains.first; chain; chain = nchain) {
- EditBone *bstart = NULL, *bend = NULL;
- EditBone *bchild = NULL, *child = NULL;
-
- /* temporarily remove chain from list of chains */
- nchain = chain->next;
- BLI_remlink(&chains, chain);
-
- /* only consider bones that are visible and selected */
- for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) {
- /* check if visible + selected */
- if (EBONE_VISIBLE(arm, ebo) &&
- ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) &&
- (ebo->flag & BONE_SELECTED) )
- {
- /* set either end or start (end gets priority, unless it is already set) */
- if (bend == NULL) {
- bend = ebo;
- bchild = child;
- }
- else
- bstart = ebo;
- }
- else {
- /* chain is broken... merge any continous segments then clear */
- if (bstart && bend)
- bones_merge(obedit, bstart, bend, bchild, &chains);
-
- bstart = NULL;
- bend = NULL;
- bchild = NULL;
- }
- }
-
- /* merge from bstart to bend if something not merged */
- if (bstart && bend)
- bones_merge(obedit, bstart, bend, bchild, &chains);
-
- /* put back link */
- BLI_insertlinkbefore(&chains, nchain, chain);
- }
-
- armature_tag_unselect(arm);
-
- BLI_freelistN(&chains);
- }
-
- /* updates */
- ED_armature_sync_selection(arm->edbo);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_merge(wmOperatorType *ot)
-{
- static EnumPropertyItem merge_types[] = {
- {1, "WITHIN_CHAIN", 0, "Within Chains", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Merge Bones";
- ot->idname = "ARMATURE_OT_merge";
- ot->description = "Merge continuous chains of selected bones";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_merge_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", merge_types, 0, "Type", "");
-}
-
-/* ************** END Add/Remove stuff in editmode ************ */
-/* *************** Tools in editmode *********** */
-
-static int armature_hide_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *ebone;
- const int invert = RNA_boolean_get(op->ptr, "unselected") ? BONE_SELECTED : 0;
-
- /* cancel if nothing selected */
- if (CTX_DATA_COUNT(C, selected_bones) == 0)
- return OPERATOR_CANCELLED;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if ((ebone->flag & BONE_SELECTED) != invert) {
- ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- ebone->flag |= BONE_HIDDEN_A;
- }
- }
- }
- ED_armature_validate_active(arm);
- ED_armature_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_hide(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Hide Selected Bones";
- ot->idname = "ARMATURE_OT_hide";
- ot->description = "Tag selected bones to not be visible in Edit Mode";
-
- /* api callbacks */
- ot->exec = armature_hide_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
-}
-
-static int armature_reveal_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (arm->layer & ebone->layer) {
- if (ebone->flag & BONE_HIDDEN_A) {
- ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- ebone->flag &= ~BONE_HIDDEN_A;
- }
- }
- }
- ED_armature_validate_active(arm);
- ED_armature_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_reveal(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Reveal Bones";
- ot->idname = "ARMATURE_OT_reveal";
- ot->description = "Unhide all bones that have been tagged to be hidden in Edit Mode";
-
- /* api callbacks */
- ot->exec = armature_reveal_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
-}
-#if 0 // remove this?
-static void hide_selected_armature_bones(Scene *scene)
-{
- Object *obedit = scene->obedit; // XXX get from context
- bArmature *arm = obedit->data;
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & BONE_SELECTED) {
- ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- ebone->flag |= BONE_HIDDEN_A;
- }
- }
- }
- ED_armature_validate_active(arm);
- ED_armature_sync_selection(arm->edbo);
-}
-
-static void hide_unselected_armature_bones(Scene *scene)
-{
- Object *obedit = scene->obedit; // XXX get from context
- bArmature *arm = obedit->data;
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- bArmature *arm = obedit->data;
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL)) {
- /* pass */
- }
- else {
- ebone->flag |= BONE_HIDDEN_A;
- }
- }
- }
-
- ED_armature_validate_active(arm);
- ED_armature_sync_selection(arm->edbo);
-}
-
-void show_all_armature_bones(Scene *scene)
-{
- Object *obedit = scene->obedit; // XXX get from context
- bArmature *arm = obedit->data;
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (arm->layer & ebone->layer) {
- if (ebone->flag & BONE_HIDDEN_A) {
- ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- ebone->flag &= ~BONE_HIDDEN_A;
- }
- }
- }
- ED_armature_validate_active(arm);
- ED_armature_sync_selection(arm->edbo);
-}
-#endif
-
-/* previously extrude_armature */
-/* context; editmode armature */
-/* if forked && mirror-edit: makes two bones with flipped names */
-static int armature_extrude_exec(bContext *C, wmOperator *op)
-{
- Object *obedit;
- bArmature *arm;
- EditBone *newbone, *ebone, *flipbone, *first = NULL;
- int a, totbone = 0, do_extrude;
- int forked = RNA_boolean_get(op->ptr, "forked");
-
- obedit = CTX_data_edit_object(C);
- arm = obedit->data;
-
- /* since we allow root extrude too, we have to make sure selection is OK */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- if (ebone->flag & BONE_ROOTSEL) {
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- if (ebone->parent->flag & BONE_TIPSEL)
- ebone->flag &= ~BONE_ROOTSEL;
- }
- }
- }
- }
-
- /* Duplicate the necessary bones */
- for (ebone = arm->edbo->first; ((ebone) && (ebone != first)); ebone = ebone->next) {
- if (EBONE_VISIBLE(arm, ebone)) {
- /* we extrude per definition the tip */
- do_extrude = FALSE;
- if (ebone->flag & (BONE_TIPSEL | BONE_SELECTED)) {
- do_extrude = TRUE;
- }
- else if (ebone->flag & BONE_ROOTSEL) {
- /* but, a bone with parent deselected we do the root... */
- if (ebone->parent && (ebone->parent->flag & BONE_TIPSEL)) {
- /* pass */
- }
- else {
- do_extrude = 2;
- }
- }
-
- if (do_extrude) {
- /* we re-use code for mirror editing... */
- flipbone = NULL;
- if (arm->flag & ARM_MIRROR_EDIT) {
- flipbone = ED_armature_bone_get_mirrored(arm->edbo, ebone);
- if (flipbone) {
- forked = 0; // we extrude 2 different bones
- if (flipbone->flag & (BONE_TIPSEL | BONE_ROOTSEL | BONE_SELECTED))
- /* don't want this bone to be selected... */
- flipbone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- }
- if ((flipbone == NULL) && (forked))
- flipbone = ebone;
- }
-
- for (a = 0; a < 2; a++) {
- if (a == 1) {
- if (flipbone == NULL)
- break;
- else {
- SWAP(EditBone *, flipbone, ebone);
- }
- }
-
- totbone++;
- newbone = MEM_callocN(sizeof(EditBone), "extrudebone");
-
- if (do_extrude == TRUE) {
- copy_v3_v3(newbone->head, ebone->tail);
- copy_v3_v3(newbone->tail, newbone->head);
- newbone->parent = ebone;
-
- newbone->flag = ebone->flag & (BONE_TIPSEL | BONE_RELATIVE_PARENTING); // copies it, in case mirrored bone
-
- if (newbone->parent) newbone->flag |= BONE_CONNECTED;
- }
- else {
- copy_v3_v3(newbone->head, ebone->head);
- copy_v3_v3(newbone->tail, ebone->head);
- newbone->parent = ebone->parent;
-
- newbone->flag = BONE_TIPSEL;
-
- if (newbone->parent && (ebone->flag & BONE_CONNECTED)) {
- newbone->flag |= BONE_CONNECTED;
- }
- }
-
- newbone->weight = ebone->weight;
- newbone->dist = ebone->dist;
- newbone->xwidth = ebone->xwidth;
- newbone->zwidth = ebone->zwidth;
- newbone->ease1 = ebone->ease1;
- newbone->ease2 = ebone->ease2;
- newbone->rad_head = ebone->rad_tail; // don't copy entire bone...
- newbone->rad_tail = ebone->rad_tail;
- newbone->segments = 1;
- newbone->layer = ebone->layer;
-
- BLI_strncpy(newbone->name, ebone->name, sizeof(newbone->name));
-
- if (flipbone && forked) { // only set if mirror edit
- if (strlen(newbone->name) < 30) {
- if (a == 0) strcat(newbone->name, "_L");
- else strcat(newbone->name, "_R");
- }
- }
- unique_editbone_name(arm->edbo, newbone->name, NULL);
-
- /* Add the new bone to the list */
- BLI_addtail(arm->edbo, newbone);
- if (!first)
- first = newbone;
-
- /* restore ebone if we were flipping */
- if (a == 1 && flipbone)
- SWAP(EditBone *, flipbone, ebone);
- }
- }
-
- /* Deselect the old bone */
- ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
- }
- }
- /* if only one bone, make this one active */
- if (totbone == 1 && first) arm->act_edbone = first;
-
- if (totbone == 0) return OPERATOR_CANCELLED;
-
- /* Transform the endpoints */
- ED_armature_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_extrude(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Extrude";
- ot->idname = "ARMATURE_OT_extrude";
- ot->description = "Create new bones from the selected joints";
-
- /* api callbacks */
- ot->exec = armature_extrude_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- RNA_def_boolean(ot->srna, "forked", 0, "Forked", "");
-}
-/* ********************** Bone Add ********************/
-
-/*op makes a new bone and returns it with its tip selected */
-
-static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
-{
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- Object *obedit = CTX_data_edit_object(C);
- EditBone *bone;
- float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
- char name[MAXBONENAME];
-
- RNA_string_get(op->ptr, "name", name);
-
- copy_v3_v3(curs, give_cursor(CTX_data_scene(C), CTX_wm_view3d(C)));
-
- /* Get inverse point for head and orientation for tail */
- invert_m4_m4(obedit->imat, obedit->obmat);
- mul_m4_v3(obedit->imat, curs);
-
- if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
- copy_m3_m4(obmat, rv3d->viewmat);
- else unit_m3(obmat);
-
- copy_m3_m4(viewmat, obedit->obmat);
- mul_m3_m3m3(totmat, obmat, viewmat);
- invert_m3_m3(imat, totmat);
-
- ED_armature_deselect_all(obedit, 0);
-
- /* Create a bone */
- bone = ED_armature_edit_bone_add(obedit->data, name);
-
- copy_v3_v3(bone->head, curs);
-
- if (rv3d && (U.flag & USER_ADD_VIEWALIGNED))
- add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1
- else
- add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_bone_primitive_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Bone";
- ot->idname = "ARMATURE_OT_bone_primitive_add";
- ot->description = "Add a new bone located at the 3D-Cursor";
-
- /* api callbacks */
- ot->exec = armature_bone_primitive_add_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_string(ot->srna, "name", "Bone", MAXBONENAME, "Name", "Name of the newly created bone");
-
-}
-
-
-/* ----------- */
-
-/* Subdivide Operators:
- * This group of operators all use the same 'exec' callback, but they are called
- * through several different operators - a combined menu (which just calls the exec in the
- * appropriate ways), and two separate ones.
- */
-
-static int armature_subdivide_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *newbone, *tbone;
- int cuts, i;
-
- /* there may not be a number_cuts property defined (for 'simple' subdivide) */
- cuts = RNA_int_get(op->ptr, "number_cuts");
-
- /* loop over all editable bones */
- // XXX the old code did this in reverse order though!
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- for (i = cuts + 1; i > 1; i--) {
- /* compute cut ratio first */
- float cutratio = 1.0f / (float)i;
- float cutratioI = 1.0f - cutratio;
-
- float val1[3];
- float val2[3];
- float val3[3];
-
- newbone = MEM_mallocN(sizeof(EditBone), "ebone subdiv");
- *newbone = *ebone;
- BLI_addtail(arm->edbo, newbone);
-
- /* calculate location of newbone->head */
- copy_v3_v3(val1, ebone->head);
- copy_v3_v3(val2, ebone->tail);
- copy_v3_v3(val3, newbone->head);
-
- val3[0] = val1[0] * cutratio + val2[0] * cutratioI;
- val3[1] = val1[1] * cutratio + val2[1] * cutratioI;
- val3[2] = val1[2] * cutratio + val2[2] * cutratioI;
-
- copy_v3_v3(newbone->head, val3);
- copy_v3_v3(newbone->tail, ebone->tail);
- copy_v3_v3(ebone->tail, newbone->head);
-
- newbone->rad_head = 0.5f * (ebone->rad_head + ebone->rad_tail);
- ebone->rad_tail = newbone->rad_head;
-
- newbone->flag |= BONE_CONNECTED;
-
- unique_editbone_name(arm->edbo, newbone->name, NULL);
-
- /* correct parent bones */
- for (tbone = arm->edbo->first; tbone; tbone = tbone->next) {
- if (tbone->parent == ebone)
- tbone->parent = newbone;
- }
- newbone->parent = ebone;
- }
- }
- CTX_DATA_END;
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_subdivide(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Subdivide Multi";
- ot->idname = "ARMATURE_OT_subdivide";
- ot->description = "Break selected bones into chains of smaller bones";
-
- /* api callbacks */
- ot->exec = armature_subdivide_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* Properties */
- prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10);
- /* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-}
-
-/* ----------- */
-
-/* Switch Direction operator:
- * Currently, this does not use context loops, as context loops do not make it
- * easy to retrieve any hierarchical/chain relationships which are necessary for
- * this to be done easily.
- */
-
-/* helper to clear BONE_TRANSFORM flags */
-static void armature_clear_swap_done_flags(bArmature *arm)
-{
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- ebone->flag &= ~BONE_TRANSFORM;
- }
-}
-
-static int armature_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (bArmature *)ob->data;
- ListBase chains = {NULL, NULL};
- LinkData *chain;
-
- /* get chains of bones (ends on chains) */
- chains_find_tips(arm->edbo, &chains);
- if (chains.first == NULL) return OPERATOR_CANCELLED;
-
- /* ensure that mirror bones will also be operated on */
- armature_tag_select_mirrored(arm);
-
- /* clear BONE_TRANSFORM flags
- * - used to prevent duplicate/cancelling operations from occurring [#34123]
- * - BONE_DONE cannot be used here as that's already used for mirroring
- */
- armature_clear_swap_done_flags(arm);
-
- /* loop over chains, only considering selected and visible bones */
- for (chain = chains.first; chain; chain = chain->next) {
- EditBone *ebo, *child = NULL, *parent = NULL;
-
- /* loop over bones in chain */
- for (ebo = chain->data; ebo; ebo = parent) {
- /* parent is this bone's original parent
- * - we store this, as the next bone that is checked is this one
- * but the value of ebo->parent may change here...
- */
- parent = ebo->parent;
-
- /* skip bone if already handled... [#34123] */
- if ((ebo->flag & BONE_TRANSFORM) == 0) {
- /* only if selected and editable */
- if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {
- /* swap head and tail coordinates */
- SWAP(float, ebo->head[0], ebo->tail[0]);
- SWAP(float, ebo->head[1], ebo->tail[1]);
- SWAP(float, ebo->head[2], ebo->tail[2]);
-
- /* do parent swapping:
- * - use 'child' as new parent
- * - connected flag is only set if points are coincidental
- */
- ebo->parent = child;
- if ((child) && equals_v3v3(ebo->head, child->tail))
- ebo->flag |= BONE_CONNECTED;
- else
- ebo->flag &= ~BONE_CONNECTED;
-
- /* get next bones
- * - child will become the new parent of next bone
- */
- child = ebo;
- }
- else {
- /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it
- * as it will be facing in opposite direction
- */
- if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) {
- ebo->parent = NULL;
- ebo->flag &= ~BONE_CONNECTED;
- }
-
- /* get next bones
- * - child will become new parent of next bone (not swapping occurred,
- * so set to NULL to prevent infinite-loop)
- */
- child = NULL;
- }
-
- /* tag as done (to prevent double-swaps) */
- ebo->flag |= BONE_TRANSFORM;
- }
- }
- }
-
- /* free chains */
- BLI_freelistN(&chains);
-
- /* clear temp flags */
- armature_clear_swap_done_flags(arm);
- armature_tag_unselect(arm);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_switch_direction(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Switch Direction";
- ot->idname = "ARMATURE_OT_switch_direction";
- ot->description = "Change the direction that a chain of bones points in (head <-> tail swap)";
-
- /* api callbacks */
- ot->exec = armature_switch_direction_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-/* ***************** Parenting *********************** */
-
-/* armature parenting options */
-#define ARM_PAR_CONNECT 1
-#define ARM_PAR_OFFSET 2
-
-/* check for null, before calling! */
-static void bone_connect_to_existing_parent(EditBone *bone)
-{
- bone->flag |= BONE_CONNECTED;
- copy_v3_v3(bone->head, bone->parent->tail);
- bone->rad_head = bone->parent->rad_tail;
-}
-
-static void bone_connect_to_new_parent(ListBase *edbo, EditBone *selbone, EditBone *actbone, short mode)
-{
- EditBone *ebone;
- float offset[3];
-
- if ((selbone->parent) && (selbone->flag & BONE_CONNECTED))
- selbone->parent->flag &= ~(BONE_TIPSEL);
-
- /* make actbone the parent of selbone */
- selbone->parent = actbone;
-
- /* in actbone tree we cannot have a loop */
- for (ebone = actbone->parent; ebone; ebone = ebone->parent) {
- if (ebone->parent == selbone) {
- ebone->parent = NULL;
- ebone->flag &= ~BONE_CONNECTED;
- }
- }
-
- if (mode == ARM_PAR_CONNECT) {
- /* Connected: Child bones will be moved to the parent tip */
- selbone->flag |= BONE_CONNECTED;
- sub_v3_v3v3(offset, actbone->tail, selbone->head);
-
- copy_v3_v3(selbone->head, actbone->tail);
- selbone->rad_head = actbone->rad_tail;
-
- add_v3_v3(selbone->tail, offset);
-
- /* offset for all its children */
- for (ebone = edbo->first; ebone; ebone = ebone->next) {
- EditBone *par;
-
- for (par = ebone->parent; par; par = par->parent) {
- if (par == selbone) {
- add_v3_v3(ebone->head, offset);
- add_v3_v3(ebone->tail, offset);
- break;
- }
- }
- }
- }
- else {
- /* Offset: Child bones will retain their distance from the parent tip */
- selbone->flag &= ~BONE_CONNECTED;
- }
-}
-
-static EnumPropertyItem prop_editarm_make_parent_types[] = {
- {ARM_PAR_CONNECT, "CONNECTED", 0, "Connected", ""},
- {ARM_PAR_OFFSET, "OFFSET", 0, "Keep Offset", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-static int armature_parent_set_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (bArmature *)ob->data;
- EditBone *actbone = CTX_data_active_bone(C);
- EditBone *actmirb = NULL;
- short val = RNA_enum_get(op->ptr, "type");
-
- /* there must be an active bone */
- if (actbone == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
- return OPERATOR_CANCELLED;
- }
- else if (arm->flag & ARM_MIRROR_EDIT) {
- /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
- * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
- * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
- * This is useful for arm-chains, for example parenting lower arm to upper arm
- * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
- * then just use actbone. Useful when doing upper arm to spine.
- */
- actmirb = ED_armature_bone_get_mirrored(arm->edbo, actbone);
- if (actmirb == NULL)
- actmirb = actbone;
- }
-
- /* if there is only 1 selected bone, we assume that that is the active bone,
- * since a user will need to have clicked on a bone (thus selecting it) to make it active
- */
- if (CTX_DATA_COUNT(C, selected_editable_bones) <= 1) {
- /* When only the active bone is selected, and it has a parent,
- * connect it to the parent, as that is the only possible outcome.
- */
- if (actbone->parent) {
- bone_connect_to_existing_parent(actbone);
-
- if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
- bone_connect_to_existing_parent(actmirb);
- }
- }
- else {
- /* Parent 'selected' bones to the active one
- * - the context iterator contains both selected bones and their mirrored copies,
- * so we assume that unselected bones are mirrored copies of some selected bone
- * - since the active one (and/or its mirror) will also be selected, we also need
- * to check that we are not trying to operate on them, since such an operation
- * would cause errors
- */
-
- /* parent selected bones to the active one */
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- if (ELEM(ebone, actbone, actmirb) == 0) {
- if (ebone->flag & BONE_SELECTED)
- bone_connect_to_new_parent(arm->edbo, ebone, actbone, val);
- else
- bone_connect_to_new_parent(arm->edbo, ebone, actmirb, val);
- }
- }
- CTX_DATA_END;
- }
-
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
-}
-
-static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
-{
- EditBone *actbone = CTX_data_active_bone(C);
- uiPopupMenu *pup = uiPupMenuBegin(C, "Make Parent ", ICON_NONE);
- uiLayout *layout = uiPupMenuLayout(pup);
- int allchildbones = 0;
-
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- if (ebone != actbone) {
- if (ebone->parent != actbone) allchildbones = 1;
- }
- }
- CTX_DATA_END;
-
- uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT);
-
- /* ob becomes parent, make the associated menus */
- if (allchildbones)
- uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET);
-
- uiPupMenuEnd(C, pup);
-
- return OPERATOR_CANCELLED;
-}
-
-void ARMATURE_OT_parent_set(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Make Parent";
- ot->idname = "ARMATURE_OT_parent_set";
- ot->description = "Set the active bone as the parent of the selected bones";
-
- /* api callbacks */
- ot->invoke = armature_parent_set_invoke;
- ot->exec = armature_parent_set_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_enum(ot->srna, "type", prop_editarm_make_parent_types, 0, "ParentType", "Type of parenting");
-}
-
-static EnumPropertyItem prop_editarm_clear_parent_types[] = {
- {1, "CLEAR", 0, "Clear Parent", ""},
- {2, "DISCONNECT", 0, "Disconnect Bone", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-static void editbone_clear_parent(EditBone *ebone, int mode)
-{
- if (ebone->parent) {
- /* for nice selection */
- ebone->parent->flag &= ~(BONE_TIPSEL);
- }
-
- if (mode == 1) ebone->parent = NULL;
- ebone->flag &= ~BONE_CONNECTED;
-}
-
-static int armature_parent_clear_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (bArmature *)ob->data;
- int val = RNA_enum_get(op->ptr, "type");
-
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- editbone_clear_parent(ebone, val);
- }
- CTX_DATA_END;
-
- ED_armature_sync_selection(arm->edbo);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_parent_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear Parent";
- ot->idname = "ARMATURE_OT_parent_clear";
- ot->description = "Remove the parent-child relationship between selected bones and their parents";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_parent_clear_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- ot->prop = RNA_def_enum(ot->srna, "type", prop_editarm_clear_parent_types, 0, "ClearType", "What way to clear parenting");
-}
-
-/* **************** Selections ******************/
-
-static int armature_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
-{
- /* Set the flags */
- CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
- {
- /* ignore bone if selection can't change */
- if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
- /* select bone */
- ebone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
- CTX_DATA_END;
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_select_inverse(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Inverse";
- ot->idname = "ARMATURE_OT_select_inverse";
- ot->description = "Flip the selection status of bones (selected -> unselected, unselected -> selected)";
-
- /* api callbacks */
- ot->exec = armature_select_inverse_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
-}
-static int armature_de_select_all_exec(bContext *C, wmOperator *op)
-{
- int action = RNA_enum_get(op->ptr, "action");
-
- if (action == SEL_TOGGLE) {
- action = SEL_SELECT;
- /* Determine if there are any selected bones
- * And therefore whether we are selecting or deselecting */
- if (CTX_DATA_COUNT(C, selected_bones) > 0)
- action = SEL_DESELECT;
- }
-
- /* Set the flags */
- CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
- {
- /* ignore bone if selection can't change */
- if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
- switch (action) {
- case SEL_SELECT:
- ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (ebone->parent)
- ebone->parent->flag |= (BONE_TIPSEL);
- break;
- case SEL_DESELECT:
- ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- break;
- case SEL_INVERT:
- if (ebone->flag & BONE_SELECTED) {
- ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- if (ebone->parent)
- ebone->parent->flag |= (BONE_TIPSEL);
- }
- break;
- }
- }
- }
- CTX_DATA_END;
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_select_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "(De)select All";
- ot->idname = "ARMATURE_OT_select_all";
- ot->description = "Toggle selection status of all bones";
-
- /* api callbacks */
- ot->exec = armature_de_select_all_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- WM_operator_properties_select_all(ot);
-}
-
-enum {
- SIMEDBONE_LENGTH = 1,
- SIMEDBONE_DIRECTION,
- SIMEDBONE_PREFIX,
- SIMEDBONE_SUFFIX,
- SIMEDBONE_LAYER
-};
-
-static EnumPropertyItem prop_similar_types[] = {
- {SIMEDBONE_LENGTH, "LENGTH", 0, "Length", ""},
- {SIMEDBONE_DIRECTION, "DIRECTION", 0, "Direction (Y axis)", ""},
- {SIMEDBONE_PREFIX, "PREFIX", 0, "Prefix", ""},
- {SIMEDBONE_SUFFIX, "SUFFIX", 0, "Suffix", ""},
- {SIMEDBONE_LAYER, "LAYER", 0, "Layer", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-/* could be used in more places */
-static void ED_armature_edit_bone_select(EditBone *ebone)
-{
- BLI_assert((ebone->flag & BONE_UNSELECTABLE) == 0);
- ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
-
- if ((ebone->flag & BONE_CONNECTED) && (ebone->parent != NULL)) {
- ebone->parent->flag |= BONE_TIPSEL;
- }
-}
-
-static void select_similar_length(bArmature *arm, EditBone *ebone_act, const float thresh)
-{
- EditBone *ebone;
-
- /* thresh is always relative to current length */
- const float len_min = ebone_act->length / (1.0f + thresh);
- const float len_max = ebone_act->length * (1.0f + thresh);
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- if ((ebone->length >= len_min) &&
- (ebone->length <= len_max))
- {
- ED_armature_edit_bone_select(ebone);
- }
- }
- }
-}
-
-static void select_similar_direction(bArmature *arm, EditBone *ebone_act, const float thresh)
-{
- EditBone *ebone;
- float dir_act[3];
- sub_v3_v3v3(dir_act, ebone_act->head, ebone_act->tail);
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- float dir[3];
- sub_v3_v3v3(dir, ebone->head, ebone->tail);
-
- if (angle_v3v3(dir_act, dir) / (float)M_PI < thresh) {
- ED_armature_edit_bone_select(ebone);
- }
- }
- }
-}
-
-static void select_similar_layer(bArmature *arm, EditBone *ebone_act)
-{
- EditBone *ebone;
-
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- if (ebone->layer & ebone_act->layer) {
- ED_armature_edit_bone_select(ebone);
- }
- }
- }
-}
-
-static void select_similar_prefix(bArmature *arm, EditBone *ebone_act)
-{
- EditBone *ebone;
-
- char body_tmp[MAX_VGROUP_NAME];
- char prefix_act[MAX_VGROUP_NAME];
-
- BKE_deform_split_prefix(ebone_act->name, prefix_act, body_tmp);
-
- if (prefix_act[0] == '\0')
- return;
-
- /* Find matches */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- char prefix_other[MAX_VGROUP_NAME];
- BKE_deform_split_prefix(ebone->name, prefix_other, body_tmp);
- if (!strcmp(prefix_act, prefix_other)) {
- ED_armature_edit_bone_select(ebone);
- }
- }
- }
-}
-
-static void select_similar_suffix(bArmature *arm, EditBone *ebone_act)
-{
- EditBone *ebone;
-
- char body_tmp[MAX_VGROUP_NAME];
- char suffix_act[MAX_VGROUP_NAME];
-
- BKE_deform_split_suffix(ebone_act->name, body_tmp, suffix_act);
-
- if (suffix_act[0] == '\0')
- return;
-
- /* Find matches */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- if (EBONE_SELECTABLE(arm, ebone)) {
- char suffix_other[MAX_VGROUP_NAME];
- BKE_deform_split_suffix(ebone->name, body_tmp, suffix_other);
- if (!strcmp(suffix_act, suffix_other)) {
- ED_armature_edit_bone_select(ebone);
- }
- }
- }
-}
-
-static int armature_select_similar_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- bArmature *arm = obedit->data;
- EditBone *ebone_act = CTX_data_active_bone(C);
-
- /* Get props */
- int type = RNA_enum_get(op->ptr, "type");
- float thresh = RNA_float_get(op->ptr, "threshold");
-
- /* Check for active bone */
- if (ebone_act == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
- return OPERATOR_CANCELLED;
- }
-
- switch (type) {
- case SIMEDBONE_LENGTH:
- select_similar_length(arm, ebone_act, thresh);
- break;
- case SIMEDBONE_DIRECTION:
- select_similar_direction(arm, ebone_act, thresh);
- break;
- case SIMEDBONE_PREFIX:
- select_similar_prefix(arm, ebone_act);
- break;
- case SIMEDBONE_SUFFIX:
- select_similar_suffix(arm, ebone_act);
- break;
- case SIMEDBONE_LAYER:
- select_similar_layer(arm, ebone_act);
- break;
- }
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_select_similar(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Similar";
- ot->idname = "ARMATURE_OT_select_similar";
-
- /* callback functions */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_select_similar_exec;
- ot->poll = ED_operator_editarmature;
- ot->description = "Select similar bones by property types";
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, 0, "Type", "");
- RNA_def_float(ot->srna, "threshold", 0.1f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
-}
-
-/* ********************* select hierarchy operator ************** */
-
-static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
-{
- Object *obedit = CTX_data_edit_object(C);
- Object *ob;
- bArmature *arm;
- EditBone *curbone, *pabone, *chbone;
- int direction = RNA_enum_get(op->ptr, "direction");
- int add_to_sel = RNA_boolean_get(op->ptr, "extend");
-
- ob = obedit;
- arm = (bArmature *)ob->data;
-
- for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
- /* only work on bone if it is visible and its selection can change */
- if (EBONE_SELECTABLE(arm, curbone)) {
- if (curbone == arm->act_edbone) {
- if (direction == BONE_SELECT_PARENT) {
- if (curbone->parent == NULL) continue;
- else pabone = curbone->parent;
-
- if (EBONE_VISIBLE(arm, pabone)) {
- pabone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_edbone = pabone;
- if (pabone->parent) pabone->parent->flag |= BONE_TIPSEL;
-
- if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- break;
- }
-
- }
- else { // BONE_SELECT_CHILD
- chbone = editbone_get_child(arm, curbone, 1);
- if (chbone == NULL) continue;
-
- if (EBONE_SELECTABLE(arm, chbone)) {
- chbone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_edbone = chbone;
-
- if (!add_to_sel) {
- curbone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL);
- if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL;
- }
- break;
- }
- }
- }
- }
- }
-
- ED_armature_sync_selection(arm->edbo);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_select_hierarchy(wmOperatorType *ot)
-{
- static EnumPropertyItem direction_items[] = {
- {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
- {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Select Hierarchy";
- ot->idname = "ARMATURE_OT_select_hierarchy";
- ot->description = "Select immediate parent/children of selected bones";
-
- /* api callbacks */
- ot->exec = armature_select_hierarchy_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- RNA_def_enum(ot->srna, "direction", direction_items,
- BONE_SELECT_PARENT, "Direction", "");
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
-}
-
-/* ***************** EditBone Alignment ********************* */
-
-/* helper to fix a ebone position if its parent has moved due to alignment*/
-static void fix_connected_bone(EditBone *ebone)
-{
- float diff[3];
-
- if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) || equals_v3v3(ebone->parent->tail, ebone->head))
- return;
-
- /* if the parent has moved we translate child's head and tail accordingly*/
- sub_v3_v3v3(diff, ebone->parent->tail, ebone->head);
- add_v3_v3(ebone->head, diff);
- add_v3_v3(ebone->tail, diff);
- return;
-}
-
-/* helper to recursively find chains of connected bones starting at ebone and fix their position */
-static void fix_editbone_connected_children(ListBase *edbo, EditBone *ebone)
-{
- EditBone *selbone;
-
- for (selbone = edbo->first; selbone; selbone = selbone->next) {
- if ((selbone->parent) && (selbone->parent == ebone) && (selbone->flag & BONE_CONNECTED)) {
- fix_connected_bone(selbone);
- fix_editbone_connected_children(edbo, selbone);
- }
- }
- return;
-}
-
-static void bone_align_to_bone(ListBase *edbo, EditBone *selbone, EditBone *actbone)
-{
- float selboneaxis[3], actboneaxis[3], length;
-
- sub_v3_v3v3(actboneaxis, actbone->tail, actbone->head);
- normalize_v3(actboneaxis);
-
- sub_v3_v3v3(selboneaxis, selbone->tail, selbone->head);
- length = len_v3(selboneaxis);
-
- mul_v3_fl(actboneaxis, length);
- add_v3_v3v3(selbone->tail, selbone->head, actboneaxis);
- selbone->roll = actbone->roll;
-
- /* if the bone being aligned has connected descendants they must be moved
- * according to their parent new position, otherwise they would be left
- * in an inconsistent state: connected but away from the parent*/
- fix_editbone_connected_children(edbo, selbone);
- return;
-}
-
-static int armature_align_bones_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (bArmature *)ob->data;
- EditBone *actbone = CTX_data_active_bone(C);
- EditBone *actmirb = NULL;
-
- /* there must be an active bone */
- if (actbone == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
- return OPERATOR_CANCELLED;
- }
- else if (arm->flag & ARM_MIRROR_EDIT) {
- /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
- * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone
- * (i.e. selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
- * This is useful for arm-chains, for example parenting lower arm to upper arm
- * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
- * then just use actbone. Useful when doing upper arm to spine.
- */
- actmirb = ED_armature_bone_get_mirrored(arm->edbo, actbone);
- if (actmirb == NULL)
- actmirb = actbone;
- }
-
- /* if there is only 1 selected bone, we assume that that is the active bone,
- * since a user will need to have clicked on a bone (thus selecting it) to make it active
- */
- if (CTX_DATA_COUNT(C, selected_editable_bones) <= 1) {
- /* When only the active bone is selected, and it has a parent,
- * align it to the parent, as that is the only possible outcome.
- */
- if (actbone->parent) {
- bone_align_to_bone(arm->edbo, actbone, actbone->parent);
-
- if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
- bone_align_to_bone(arm->edbo, actmirb, actmirb->parent);
- }
- }
- else {
- /* Align 'selected' bones to the active one
- * - the context iterator contains both selected bones and their mirrored copies,
- * so we assume that unselected bones are mirrored copies of some selected bone
- * - since the active one (and/or its mirror) will also be selected, we also need
- * to check that we are not trying to operate on them, since such an operation
- * would cause errors
- */
-
- /* align selected bones to the active one */
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- if (ELEM(ebone, actbone, actmirb) == 0) {
- if (ebone->flag & BONE_SELECTED)
- bone_align_to_bone(arm->edbo, ebone, actbone);
- else
- bone_align_to_bone(arm->edbo, ebone, actmirb);
- }
- }
- CTX_DATA_END;
- }
-
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_align(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Align Bones";
- ot->idname = "ARMATURE_OT_align";
- ot->description = "Align selected bones to the active bone (or to their parent)";
-
- /* api callbacks */
- ot->invoke = WM_operator_confirm;
- ot->exec = armature_align_bones_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ***************** Pose tools ********************* */
-
-/* XXX bone_looper is only to be used when we want to access settings
- * (i.e. editability/visibility/selected) that context doesn't offer */
-static int bone_looper(Object *ob, Bone *bone, void *data,
- int (*bone_func)(Object *, Bone *, void *))
-{
- /* We want to apply the function bone_func to every bone
- * in an armature -- feed bone_looper the first bone and
- * a pointer to the bone_func and watch it go!. The int count
- * can be useful for counting bones with a certain property
- * (e.g. skinnable)
- */
- int count = 0;
-
- if (bone) {
- /* only do bone_func if the bone is non null */
- count += bone_func(ob, bone, data);
-
- /* try to execute bone_func for the first child */
- count += bone_looper(ob, bone->childbase.first, data, bone_func);
-
- /* try to execute bone_func for the next bone at this
- * depth of the recursion.
- */
- count += bone_looper(ob, bone->next, data, bone_func);
- }
-
- return count;
-}
-
-/* called from editview.c, for mode-less pose selection */
-/* assumes scene obact and basact is still on old situation */
-int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits,
- short extend, short deselect, short toggle)
-{
- Object *ob = base->object;
- Bone *nearBone;
-
- if (!ob || !ob->pose) return 0;
-
- nearBone = get_bone_from_selectbuffer(scene, base, buffer, hits, 1);
-
- /* if the bone cannot be affected, don't do anything */
- if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) {
- Object *ob_act = OBACT;
- bArmature *arm = ob->data;
-
- /* since we do unified select, we don't shift+select a bone if the
- * armature object was not active yet.
- * note, special exception for armature mode so we can do multi-select
- * we could check for multi-select explicitly but think its fine to
- * always give predictable behavior in weight paint mode - campbell */
- if ((!extend && !deselect && !toggle) ||
- ((ob_act && (ob_act != ob) && (ob_act->mode & OB_MODE_WEIGHT_PAINT) == 0)))
- {
- ED_pose_deselectall(ob, 0);
- nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_bone = nearBone;
- }
- else {
- if (extend) {
- nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_bone = nearBone;
- }
- else if (deselect) {
- nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if (toggle) {
- if (nearBone->flag & BONE_SELECTED) {
- /* if not active, we make it active */
- if (nearBone != arm->act_bone) {
- arm->act_bone = nearBone;
- }
- else {
- nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- }
- else {
- nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_bone = nearBone;
- }
- }
- }
-
- if (ob_act) {
- /* in weightpaint we select the associated vertex group too */
- if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
- if (nearBone == arm->act_bone) {
- ED_vgroup_select_by_name(ob_act, nearBone->name);
- DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
- }
- }
- /* if there are some dependencies for visualizing armature state
- * (e.g. Mask Modifier in 'Armature' mode), force update
- */
- else if (arm->flag & ARM_HAS_VIZ_DEPS) {
- DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
- }
- }
- }
-
- return nearBone != NULL;
-}
-
-/* test==0: deselect all
- * test==1: swap select (apply to all the opposite of current situation)
- * test==2: only clear active tag
- * test==3: swap select (no test / inverse selection status of all independently)
- */
-void ED_pose_deselectall(Object *ob, int test)
-{
- bArmature *arm = ob->data;
- bPoseChannel *pchan;
- int selectmode = 0;
-
- /* we call this from outliner too */
- if (ob->pose == NULL) {
- return;
- }
-
- /* Determine if we're selecting or deselecting */
- if (test == 1) {
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (PBONE_VISIBLE(arm, pchan->bone)) {
- if (pchan->bone->flag & BONE_SELECTED)
- break;
- }
- }
-
- if (pchan == NULL)
- selectmode = 1;
- }
- else if (test == 2)
- selectmode = 2;
-
- /* Set the flags accordingly */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- /* ignore the pchan if it isn't visible or if its selection cannot be changed */
- if ((pchan->bone->layer & arm->layer) && !(pchan->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
- if (test == 3) {
- pchan->bone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- if (selectmode == 0) pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- else if (selectmode == 1) pchan->bone->flag |= BONE_SELECTED;
- }
- }
- }
-}
-
-static int bone_skinnable_cb(Object *ob, Bone *bone, void *datap)
-{
- /* Bones that are deforming
- * are regarded to be "skinnable" and are eligible for
- * auto-skinning.
- *
- * This function performs 2 functions:
- *
- * a) It returns 1 if the bone is skinnable.
- * If we loop over all bones with this
- * function, we can count the number of
- * skinnable bones.
- * b) If the pointer data is non null,
- * it is treated like a handle to a
- * bone pointer -- the bone pointer
- * is set to point at this bone, and
- * the pointer the handle points to
- * is incremented to point to the
- * next member of an array of pointers
- * to bones. This way we can loop using
- * this function to construct an array of
- * pointers to bones that point to all
- * skinnable bones.
- */
- Bone ***hbone;
- int a, segments;
- struct { Object *armob; void *list; int heat; } *data = datap;
-
- if (!(ob->mode & OB_MODE_WEIGHT_PAINT) || !(bone->flag & BONE_HIDDEN_P)) {
- if (!(bone->flag & BONE_NO_DEFORM)) {
- if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name))
- segments = bone->segments;
- else
- segments = 1;
-
- if (data->list != NULL) {
- hbone = (Bone ***) &data->list;
-
- for (a = 0; a < segments; a++) {
- **hbone = bone;
- ++*hbone;
- }
- }
- return segments;
- }
- }
- return 0;
-}
-
-static int vgroup_add_unique_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
-{
- /* This group creates a vertex group to ob that has the
- * same name as bone (provided the bone is skinnable).
- * If such a vertex group aleady exist the routine exits.
- */
- if (!(bone->flag & BONE_NO_DEFORM)) {
- if (!defgroup_find_name(ob, bone->name)) {
- ED_vgroup_add_name(ob, bone->name);
- return 1;
- }
- }
- return 0;
-}
-
-static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
-{
- /* Bones that are deforming
- * are regarded to be "skinnable" and are eligible for
- * auto-skinning.
- *
- * This function performs 2 functions:
- *
- * a) If the bone is skinnable, it creates
- * a vertex group for ob that has
- * the name of the skinnable bone
- * (if one doesn't exist already).
- * b) If the pointer data is non null,
- * it is treated like a handle to a
- * bDeformGroup pointer -- the
- * bDeformGroup pointer is set to point
- * to the deform group with the bone's
- * name, and the pointer the handle
- * points to is incremented to point to the
- * next member of an array of pointers
- * to bDeformGroups. This way we can loop using
- * this function to construct an array of
- * pointers to bDeformGroups, all with names
- * of skinnable bones.
- */
- bDeformGroup ***hgroup, *defgroup = NULL;
- int a, segments;
- struct { Object *armob; void *list; int heat; } *data = datap;
- int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
- bArmature *arm = data->armob->data;
-
- if (!wpmode || !(bone->flag & BONE_HIDDEN_P)) {
- if (!(bone->flag & BONE_NO_DEFORM)) {
- if (data->heat && data->armob->pose && BKE_pose_channel_find_name(data->armob->pose, bone->name))
- segments = bone->segments;
- else
- segments = 1;
-
- if (!wpmode || ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED)))
- if (!(defgroup = defgroup_find_name(ob, bone->name)))
- defgroup = ED_vgroup_add_name(ob, bone->name);
-
- if (data->list != NULL) {
- hgroup = (bDeformGroup ***) &data->list;
-
- for (a = 0; a < segments; a++) {
- **hgroup = defgroup;
- ++*hgroup;
- }
- }
- return segments;
- }
- }
- return 0;
-}
-
-static void add_vgroups__mapFunc(void *userData, int index, const float co[3],
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
-{
- /* DerivedMesh mapFunc for getting final coords in weight paint mode */
-
- float (*verts)[3] = userData;
- copy_v3_v3(verts[index], co);
-}
-
-static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist,
- bDeformGroup **dgrouplist, bDeformGroup **dgroupflip,
- float (*root)[3], float (*tip)[3], int *selected, float scale)
-{
- /* Create vertex group weights from envelopes */
-
- Bone *bone;
- bDeformGroup *dgroup;
- float distance;
- int i, iflip, j;
-
- /* for each vertex in the mesh */
- for (i = 0; i < mesh->totvert; i++) {
- iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, i) : 0;
-
- /* for each skinnable bone */
- for (j = 0; j < numbones; ++j) {
- if (!selected[j])
- continue;
-
- bone = bonelist[j];
- dgroup = dgrouplist[j];
-
- /* store the distance-factor from the vertex to the bone */
- distance = distfactor_to_bone(verts[i], root[j], tip[j],
- bone->rad_head * scale, bone->rad_tail * scale, bone->dist * scale);
-
- /* add the vert to the deform group if (weight != 0.0) */
- if (distance != 0.0f)
- ED_vgroup_vert_add(ob, dgroup, i, distance, WEIGHT_REPLACE);
- else
- ED_vgroup_vert_remove(ob, dgroup, i);
-
- /* do same for mirror */
- if (dgroupflip && dgroupflip[j] && iflip >= 0) {
- if (distance != 0.0f)
- ED_vgroup_vert_add(ob, dgroupflip[j], iflip, distance,
- WEIGHT_REPLACE);
- else
- ED_vgroup_vert_remove(ob, dgroupflip[j], iflip);
- }
- }
- }
-}
-
-static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, Object *par, int heat, int mirror)
-{
- /* This functions implements the automatic computation of vertex group
- * weights, either through envelopes or using a heat equilibrium.
- *
- * This function can be called both when parenting a mesh to an armature,
- * or in weightpaint + posemode. In the latter case selection is taken
- * into account and vertex weights can be mirrored.
- *
- * The mesh vertex positions used are either the final deformed coords
- * from the derivedmesh in weightpaint mode, the final subsurf coords
- * when parenting, or simply the original mesh coords.
- */
-
- bArmature *arm = par->data;
- Bone **bonelist, *bone;
- bDeformGroup **dgrouplist, **dgroupflip;
- bDeformGroup *dgroup;
- bPoseChannel *pchan;
- Mesh *mesh;
- Mat4 *bbone = NULL;
- float (*root)[3], (*tip)[3], (*verts)[3];
- int *selected;
- int numbones, vertsfilled = 0, i, j, segments = 0;
- int wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
- struct { Object *armob; void *list; int heat; } looper_data;
-
- looper_data.armob = par;
- looper_data.heat = heat;
- looper_data.list = NULL;
-
- /* count the number of skinnable bones */
- numbones = bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb);
-
- if (numbones == 0)
- return;
-
- if (ED_vgroup_data_create(ob->data) == FALSE)
- return;
-
- /* create an array of pointer to bones that are skinnable
- * and fill it with all of the skinnable bones */
- bonelist = MEM_callocN(numbones * sizeof(Bone *), "bonelist");
- looper_data.list = bonelist;
- bone_looper(ob, arm->bonebase.first, &looper_data, bone_skinnable_cb);
-
- /* create an array of pointers to the deform groups that
- * correspond to the skinnable bones (creating them
- * as necessary. */
- dgrouplist = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist");
- dgroupflip = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgroupflip");
-
- looper_data.list = dgrouplist;
- bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable_cb);
-
- /* create an array of root and tip positions transformed into
- * global coords */
- root = MEM_callocN(numbones * sizeof(float) * 3, "root");
- tip = MEM_callocN(numbones * sizeof(float) * 3, "tip");
- selected = MEM_callocN(numbones * sizeof(int), "selected");
-
- for (j = 0; j < numbones; ++j) {
- bone = bonelist[j];
- dgroup = dgrouplist[j];
-
- /* handle bbone */
- if (heat) {
- if (segments == 0) {
- segments = 1;
- bbone = NULL;
-
- if ((par->pose) && (pchan = BKE_pose_channel_find_name(par->pose, bone->name))) {
- if (bone->segments > 1) {
- segments = bone->segments;
- bbone = b_bone_spline_setup(pchan, 1);
- }
- }
- }
-
- segments--;
- }
-
- /* compute root and tip */
- if (bbone) {
- mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]);
- if ((segments + 1) < bone->segments) {
- mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]);
- }
- else {
- copy_v3_v3(tip[j], bone->arm_tail);
- }
- }
- else {
- copy_v3_v3(root[j], bone->arm_head);
- copy_v3_v3(tip[j], bone->arm_tail);
- }
-
- mul_m4_v3(par->obmat, root[j]);
- mul_m4_v3(par->obmat, tip[j]);
-
- /* set selected */
- if (wpmode) {
- if ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))
- selected[j] = 1;
- }
- else
- selected[j] = 1;
-
- /* find flipped group */
- if (dgroup && mirror) {
- char name[MAXBONENAME];
-
- // 0 = don't strip off number extensions
- flip_side_name(name, dgroup->name, FALSE);
- dgroupflip[j] = defgroup_find_name(ob, name);
- }
- }
-
- /* create verts */
- mesh = (Mesh *)ob->data;
- verts = MEM_callocN(mesh->totvert * sizeof(*verts), "closestboneverts");
-
- if (wpmode) {
- /* if in weight paint mode, use final verts from derivedmesh */
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
-
- if (dm->foreachMappedVert) {
- dm->foreachMappedVert(dm, add_vgroups__mapFunc, (void *)verts);
- vertsfilled = 1;
- }
-
- dm->release(dm);
- }
- else if (modifiers_findByType(ob, eModifierType_Subsurf)) {
- /* is subsurf on? Lets use the verts on the limit surface then.
- * = same amount of vertices as mesh, but vertices moved to the
- * subsurfed position, like for 'optimal'. */
- subsurf_calculate_limit_positions(mesh, verts);
- vertsfilled = 1;
- }
-
- /* transform verts to global space */
- for (i = 0; i < mesh->totvert; i++) {
- if (!vertsfilled)
- copy_v3_v3(verts[i], mesh->mvert[i].co);
- mul_m4_v3(ob->obmat, verts[i]);
- }
-
- /* compute the weights based on gathered vertices and bones */
- if (heat) {
- const char *error = NULL;
- heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip,
- root, tip, selected, &error);
-
- if (error) {
- BKE_report(reports, RPT_WARNING, error);
- }
- }
- else {
- envelope_bone_weighting(ob, mesh, verts, numbones, bonelist, dgrouplist,
- dgroupflip, root, tip, selected, mat4_to_scale(par->obmat));
- }
-
- /* only generated in some cases but can call anyway */
- mesh_octree_table(ob, NULL, NULL, 'e');
-
- /* free the memory allocated */
- MEM_freeN(bonelist);
- MEM_freeN(dgrouplist);
- MEM_freeN(dgroupflip);
- MEM_freeN(root);
- MEM_freeN(tip);
- MEM_freeN(selected);
- MEM_freeN(verts);
-}
-
-void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob, Object *par, int mode, int mirror)
-{
- /* Lets try to create some vertex groups
- * based on the bones of the parent armature.
- */
- bArmature *arm = par->data;
-
- if (mode == ARM_GROUPS_NAME) {
- const int defbase_tot = BLI_countlist(&ob->defbase);
- int defbase_add;
- /* Traverse the bone list, trying to create empty vertex
- * groups corresponding to the bone.
- */
- defbase_add = bone_looper(ob, arm->bonebase.first, NULL, vgroup_add_unique_bone_cb);
-
- if (defbase_add) {
- /* its possible there are DWeight's outside the range of the current
- * objects deform groups, in this case the new groups wont be empty [#33889] */
- ED_vgroup_data_clamp_range(ob->data, defbase_tot);
- }
- }
- else if (mode == ARM_GROUPS_ENVELOPE || mode == ARM_GROUPS_AUTO) {
- /* Traverse the bone list, trying to create vertex groups
- * that are populated with the vertices for which the
- * bone is closest.
- */
- add_verts_to_dgroups(reports, scene, ob, par, (mode == ARM_GROUPS_AUTO), mirror);
- }
-}
-/* ************* Clear Pose *****************************/
-
-/* clear scale of pose-channel */
-static void pchan_clear_scale(bPoseChannel *pchan)
-{
- if ((pchan->protectflag & OB_LOCK_SCALEX) == 0)
- pchan->size[0] = 1.0f;
- if ((pchan->protectflag & OB_LOCK_SCALEY) == 0)
- pchan->size[1] = 1.0f;
- if ((pchan->protectflag & OB_LOCK_SCALEZ) == 0)
- pchan->size[2] = 1.0f;
-}
-
-/* clear location of pose-channel */
-static void pchan_clear_loc(bPoseChannel *pchan)
-{
- if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
- pchan->loc[0] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
- pchan->loc[1] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
- pchan->loc[2] = 0.0f;
-}
-
-/* clear rotation of pose-channel */
-static void pchan_clear_rot(bPoseChannel *pchan)
-{
- if (pchan->protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) {
- /* check if convert to eulers for locking... */
- if (pchan->protectflag & OB_LOCK_ROT4D) {
- /* perform clamping on a component by component basis */
- if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- if ((pchan->protectflag & OB_LOCK_ROTW) == 0)
- pchan->rotAngle = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
- pchan->rotAxis[0] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
- pchan->rotAxis[1] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
- pchan->rotAxis[2] = 0.0f;
-
- /* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */
- if (IS_EQF(pchan->rotAxis[0], pchan->rotAxis[1]) && IS_EQF(pchan->rotAxis[1], pchan->rotAxis[2]))
- pchan->rotAxis[1] = 1.0f;
- }
- else if (pchan->rotmode == ROT_MODE_QUAT) {
- if ((pchan->protectflag & OB_LOCK_ROTW) == 0)
- pchan->quat[0] = 1.0f;
- if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
- pchan->quat[1] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
- pchan->quat[2] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
- pchan->quat[3] = 0.0f;
- }
- else {
- /* the flag may have been set for the other modes, so just ignore the extra flag... */
- if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
- pchan->eul[0] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
- pchan->eul[1] = 0.0f;
- if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
- pchan->eul[2] = 0.0f;
- }
- }
- else {
- /* perform clamping using euler form (3-components) */
- float eul[3], oldeul[3], quat1[4] = {0};
- float qlen = 0.0f;
-
- if (pchan->rotmode == ROT_MODE_QUAT) {
- qlen = normalize_qt_qt(quat1, pchan->quat);
- quat_to_eul(oldeul, quat1);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
- }
- else {
- copy_v3_v3(oldeul, pchan->eul);
- }
-
- eul[0] = eul[1] = eul[2] = 0.0f;
-
- if (pchan->protectflag & OB_LOCK_ROTX)
- eul[0] = oldeul[0];
- if (pchan->protectflag & OB_LOCK_ROTY)
- eul[1] = oldeul[1];
- if (pchan->protectflag & OB_LOCK_ROTZ)
- eul[2] = oldeul[2];
-
- if (pchan->rotmode == ROT_MODE_QUAT) {
- eul_to_quat(pchan->quat, eul);
-
- /* restore original quat size */
- mul_qt_fl(pchan->quat, qlen);
-
- /* quaternions flip w sign to accumulate rotations correctly */
- if ((quat1[0] < 0.0f && pchan->quat[0] > 0.0f) || (quat1[0] > 0.0f && pchan->quat[0] < 0.0f)) {
- mul_qt_fl(pchan->quat, -1.0f);
- }
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
- }
- else {
- copy_v3_v3(pchan->eul, eul);
- }
- }
- } /* Duplicated in source/blender/editors/object/object_transform.c */
- else {
- if (pchan->rotmode == ROT_MODE_QUAT) {
- unit_qt(pchan->quat);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- /* by default, make rotation of 0 radians around y-axis (roll) */
- unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
- }
- else {
- zero_v3(pchan->eul);
- }
- }
-}
-
-/* clear loc/rot/scale of pose-channel */
-static void pchan_clear_transforms(bPoseChannel *pchan)
-{
- pchan_clear_loc(pchan);
- pchan_clear_rot(pchan);
- pchan_clear_scale(pchan);
-}
-
-/* --------------- */
-
-/* generic exec for clear-pose operators */
-static int pose_clear_transform_generic_exec(bContext *C, wmOperator *op,
- void (*clear_func)(bPoseChannel *), const char default_ksName[])
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- short autokey = 0;
-
- /* sanity checks */
- if (ELEM(NULL, clear_func, default_ksName)) {
- BKE_report(op->reports, RPT_ERROR, "Programming error: missing clear transform function or keying set name");
- return OPERATOR_CANCELLED;
- }
-
- /* only clear relevant transforms for selected bones */
- CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones)
- {
- /* run provided clearing function */
- clear_func(pchan);
-
- /* do auto-keyframing as appropriate */
- if (autokeyframe_cfra_can_key(scene, &ob->id)) {
- /* clear any unkeyed tags */
- if (pchan->bone)
- pchan->bone->flag &= ~BONE_UNKEYED;
-
- /* tag for autokeying later */
- autokey = 1;
- }
- else {
- /* add unkeyed tags */
- if (pchan->bone)
- pchan->bone->flag |= BONE_UNKEYED;
- }
- }
- CTX_DATA_END;
-
- /* perform autokeying on the bones if needed */
- if (autokey) {
- /* get KeyingSet to use */
- KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
-
- /* insert keyframes */
- ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
-
- /* now recalculate paths */
- if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS))
- ED_pose_recalculate_paths(scene, ob);
- }
-
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
-
- return OPERATOR_FINISHED;
-}
-
-/* --------------- */
-
-static int pose_clear_scale_exec(bContext *C, wmOperator *op)
-{
- return pose_clear_transform_generic_exec(C, op, pchan_clear_scale, ANIM_KS_SCALING_ID);
-}
-
-void POSE_OT_scale_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear Pose Scale";
- ot->idname = "POSE_OT_scale_clear";
- ot->description = "Reset scaling of selected bones to their default values";
-
- /* api callbacks */
- ot->exec = pose_clear_scale_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-static int pose_clear_rot_exec(bContext *C, wmOperator *op)
-{
- return pose_clear_transform_generic_exec(C, op, pchan_clear_rot, ANIM_KS_ROTATION_ID);
-}
-
-void POSE_OT_rot_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear Pose Rotation";
- ot->idname = "POSE_OT_rot_clear";
- ot->description = "Reset rotations of selected bones to their default values";
-
- /* api callbacks */
- ot->exec = pose_clear_rot_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-static int pose_clear_loc_exec(bContext *C, wmOperator *op)
-{
- return pose_clear_transform_generic_exec(C, op, pchan_clear_loc, ANIM_KS_LOCATION_ID);
-}
-
-void POSE_OT_loc_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear Pose Location";
- ot->idname = "POSE_OT_loc_clear";
- ot->description = "Reset locations of selected bones to their default values";
-
- /* api callbacks */
- ot->exec = pose_clear_loc_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-static int pose_clear_transforms_exec(bContext *C, wmOperator *op)
-{
- return pose_clear_transform_generic_exec(C, op, pchan_clear_transforms, ANIM_KS_LOC_ROT_SCALE_ID);
-}
-
-void POSE_OT_transforms_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear Pose Transforms";
- ot->idname = "POSE_OT_transforms_clear";
- ot->description = "Reset location, rotation, and scaling of selected bones to their default values";
-
- /* api callbacks */
- ot->exec = pose_clear_transforms_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ***************** selections ********************** */
-
-static int pose_de_select_all_exec(bContext *C, wmOperator *op)
-{
- int action = RNA_enum_get(op->ptr, "action");
-
- Scene *scene = CTX_data_scene(C);
- Object *ob = ED_object_context(C);
- bArmature *arm = ob->data;
- int multipaint = scene->toolsettings->multipaint;
-
- if (action == SEL_TOGGLE) {
- action = CTX_DATA_COUNT(C, selected_pose_bones) ? SEL_DESELECT : SEL_SELECT;
- }
-
- /* Set the flags */
- CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones)
- {
- /* select pchan only if selectable, but deselect works always */
- switch (action) {
- case SEL_SELECT:
- if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)
- pchan->bone->flag |= BONE_SELECTED;
- break;
- case SEL_DESELECT:
- pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- break;
- case SEL_INVERT:
- if (pchan->bone->flag & BONE_SELECTED) {
- pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
- pchan->bone->flag |= BONE_SELECTED;
- }
- break;
- }
- }
- CTX_DATA_END;
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
-
- /* weightpaint or mask modifiers need depsgraph updates */
- if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) {
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_select_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "(De)select All";
- ot->idname = "POSE_OT_select_all";
- ot->description = "Toggle selection status of all bones";
-
- /* api callbacks */
- ot->exec = pose_de_select_all_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- WM_operator_properties_select_all(ot);
-}
-
-static int pose_select_parent_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (bArmature *)ob->data;
- bPoseChannel *pchan, *parent;
-
- /* Determine if there is an active bone */
- pchan = CTX_data_active_pose_bone(C);
- if (pchan) {
- parent = pchan->parent;
- if ((parent) && !(parent->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
- parent->bone->flag |= BONE_SELECTED;
- arm->act_bone = parent->bone;
- }
- else {
- return OPERATOR_CANCELLED;
- }
- }
- else {
- return OPERATOR_CANCELLED;
- }
-
- /* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_select_parent(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Parent Bone";
- ot->idname = "POSE_OT_select_parent";
- ot->description = "Select bones that are parents of the currently selected bones";
-
- /* api callbacks */
- ot->exec = pose_select_parent_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
-}
-
-/* ************* hide/unhide pose bones ******************* */
-
-static int hide_selected_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
-{
- bArmature *arm = ob->data;
-
- if (arm->layer & bone->layer) {
- if (bone->flag & BONE_SELECTED) {
- bone->flag |= BONE_HIDDEN_P;
- bone->flag &= ~BONE_SELECTED;
- if (arm->act_bone == bone)
- arm->act_bone = NULL;
- }
- }
- return 0;
-}
-
-static int hide_unselected_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
-{
- bArmature *arm = ob->data;
-
- if (arm->layer & bone->layer) {
- /* hrm... typo here? */
- if ((bone->flag & BONE_SELECTED) == 0) {
- bone->flag |= BONE_HIDDEN_P;
- if (arm->act_bone == bone)
- arm->act_bone = NULL;
- }
- }
- return 0;
-}
-
-/* active object is armature in posemode, poll checked */
-static int pose_hide_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = ob->data;
-
- if (RNA_boolean_get(op->ptr, "unselected"))
- bone_looper(ob, arm->bonebase.first, NULL, hide_unselected_pose_bone_cb);
- else
- bone_looper(ob, arm->bonebase.first, NULL, hide_selected_pose_bone_cb);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_hide(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Hide Selected";
- ot->idname = "POSE_OT_hide";
- ot->description = "Tag selected bones to not be visible in Pose Mode";
-
- /* api callbacks */
- ot->exec = pose_hide_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "");
-}
-
-static int show_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
-{
- bArmature *arm = ob->data;
-
- if (arm->layer & bone->layer) {
- if (bone->flag & BONE_HIDDEN_P) {
- bone->flag &= ~BONE_HIDDEN_P;
- bone->flag |= BONE_SELECTED;
- }
- }
-
- return 0;
-}
-
-/* active object is armature in posemode, poll checked */
-static int pose_reveal_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = ob->data;
-
- bone_looper(ob, arm->bonebase.first, NULL, show_pose_bone_cb);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_reveal(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Reveal Selected";
- ot->idname = "POSE_OT_reveal";
- ot->description = "Unhide all bones that have been tagged to be hidden in Pose Mode";
-
- /* api callbacks */
- ot->exec = pose_reveal_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ************* RENAMING DISASTERS ************ */
-
-static int bone_unique_check(void *arg, const char *name)
-{
- return BKE_armature_find_bone_name((bArmature *)arg, name) != NULL;
-}
-
-static void unique_bone_name(bArmature *arm, char *name)
-{
- BLI_uniquename_cb(bone_unique_check, (void *)arm, "Bone", '.', name, sizeof(((Bone *)NULL)->name));
-}
-
-/* helper call for armature_bone_rename */
-static void constraint_bone_name_fix(Object *ob, ListBase *conlist, char *oldname, char *newname)
-{
- bConstraint *curcon;
- bConstraintTarget *ct;
-
- for (curcon = conlist->first; curcon; curcon = curcon->next) {
- bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon);
- ListBase targets = {NULL, NULL};
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar == ob) {
- if (!strcmp(ct->subtarget, oldname) )
- BLI_strncpy(ct->subtarget, newname, MAXBONENAME);
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
- }
-}
-
-/* called by UI for renaming a bone */
-/* warning: make sure the original bone was not renamed yet! */
-/* seems messy, but thats what you get with not using pointers but channel names :) */
-void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *newnamep)
-{
- Object *ob;
- char newname[MAXBONENAME];
- char oldname[MAXBONENAME];
-
- /* names better differ! */
- if (strncmp(oldnamep, newnamep, MAXBONENAME)) {
-
- /* we alter newname string... so make copy */
- BLI_strncpy(newname, newnamep, MAXBONENAME);
- /* we use oldname for search... so make copy */
- BLI_strncpy(oldname, oldnamep, MAXBONENAME);
-
- /* now check if we're in editmode, we need to find the unique name */
- if (arm->edbo) {
- EditBone *eBone = editbone_name_exists(arm->edbo, oldname);
-
- if (eBone) {
- unique_editbone_name(arm->edbo, newname, NULL);
- BLI_strncpy(eBone->name, newname, MAXBONENAME);
- }
- else return;
- }
- else {
- Bone *bone = BKE_armature_find_bone_name(arm, oldname);
-
- if (bone) {
- unique_bone_name(arm, newname);
- BLI_strncpy(bone->name, newname, MAXBONENAME);
- }
- else return;
- }
-
- /* do entire dbase - objects */
- for (ob = G.main->object.first; ob; ob = ob->id.next) {
- ModifierData *md;
-
- /* we have the object using the armature */
- if (arm == ob->data) {
- Object *cob;
-
- /* Rename the pose channel, if it exists */
- if (ob->pose) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, oldname);
- if (pchan) {
- BLI_strncpy(pchan->name, newname, MAXBONENAME);
-
- if (ob->pose->chanhash) {
- GHash *gh = ob->pose->chanhash;
-
- /* remove the old hash entry, and replace with the new name */
- BLI_ghash_remove(gh, oldname, NULL, NULL);
- BLI_ghash_insert(gh, pchan->name, pchan);
- }
- }
- }
-
- /* Update any object constraints to use the new bone name */
- for (cob = G.main->object.first; cob; cob = cob->id.next) {
- if (cob->constraints.first)
- constraint_bone_name_fix(ob, &cob->constraints, oldname, newname);
- if (cob->pose) {
- bPoseChannel *pchan;
- for (pchan = cob->pose->chanbase.first; pchan; pchan = pchan->next) {
- constraint_bone_name_fix(ob, &pchan->constraints, oldname, newname);
- }
- }
- }
- }
-
- /* See if an object is parented to this armature */
- if (ob->parent && (ob->parent->data == arm)) {
- if (ob->partype == PARBONE) {
- /* bone name in object */
- if (!strcmp(ob->parsubstr, oldname))
- BLI_strncpy(ob->parsubstr, newname, MAXBONENAME);
- }
- }
-
- if (modifiers_usesArmature(ob, arm)) {
- bDeformGroup *dg = defgroup_find_name(ob, oldname);
- if (dg) {
- BLI_strncpy(dg->name, newname, MAXBONENAME);
- }
- }
-
- /* fix modifiers that might be using this name */
- for (md = ob->modifiers.first; md; md = md->next) {
- if (md->type == eModifierType_Hook) {
- HookModifierData *hmd = (HookModifierData *)md;
-
- /* uses armature, so may use the affected bone name */
- if (hmd->object && (hmd->object->data == arm)) {
- if (!strcmp(hmd->subtarget, oldname))
- BLI_strncpy(hmd->subtarget, newname, MAXBONENAME);
- }
- }
- }
- }
-
- /* Fix all animdata that may refer to this bone - we can't just do the ones attached to objects, since
- * other ID-blocks may have drivers referring to this bone [#29822]
- */
- {
-
- BKE_all_animdata_fix_paths_rename(&arm->id, "pose.bones", oldname, newname);
- }
-
- /* correct view locking */
- {
- bScreen *screen;
- for (screen = G.main->screen.first; screen; screen = screen->id.next) {
- ScrArea *sa;
- /* add regions */
- 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) {
- View3D *v3d = (View3D *)sl;
- if (v3d->ob_centre && v3d->ob_centre->data == arm) {
- if (!strcmp(v3d->ob_centre_bone, oldname)) {
- BLI_strncpy(v3d->ob_centre_bone, newname, MAXBONENAME);
- }
- }
- }
- }
- }
- }
- }
- }
-}
-
-
-static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm;
- char newname[MAXBONENAME];
-
- /* paranoia checks */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
- arm = ob->data;
-
- /* loop through selected bones, auto-naming them */
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- flip_side_name(newname, ebone->name, TRUE); // 1 = do strip off number extensions
- ED_armature_bone_rename(arm, ebone->name, newname);
- }
- CTX_DATA_END;
-
- /* since we renamed stuff... */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_flip_names(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Flip Names";
- ot->idname = "ARMATURE_OT_flip_names";
- ot->description = "Flips (and corrects) the axis suffixes of the names of selected bones";
-
- /* api callbacks */
- ot->exec = armature_flip_names_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-static int armature_autoside_names_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm;
- char newname[MAXBONENAME];
- short axis = RNA_enum_get(op->ptr, "type");
-
- /* paranoia checks */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
- arm = ob->data;
-
- /* loop through selected bones, auto-naming them */
- CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
- {
- BLI_strncpy(newname, ebone->name, sizeof(newname));
- if (bone_autoside_name(newname, 1, axis, ebone->head[axis], ebone->tail[axis]))
- ED_armature_bone_rename(arm, ebone->name, newname);
- }
- CTX_DATA_END;
-
- /* since we renamed stuff... */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_autoside_names(wmOperatorType *ot)
-{
- static EnumPropertyItem axis_items[] = {
- {0, "XAXIS", 0, "X-Axis", "Left/Right"},
- {1, "YAXIS", 0, "Y-Axis", "Front/Back"},
- {2, "ZAXIS", 0, "Z-Axis", "Top/Bottom"},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "AutoName by Axis";
- ot->idname = "ARMATURE_OT_autoside_names";
- ot->description = "Automatically renames the selected bones according to which side of the target axis they fall on";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_autoside_names_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* settings */
- ot->prop = RNA_def_enum(ot->srna, "type", axis_items, 0, "Axis", "Axis tag names with");
-}
-
-
-
-/* if editbone (partial) selected, copy data */
-/* context; editmode armature, with mirror editing enabled */
-void transform_armature_mirror_update(Object *obedit)
-{
- bArmature *arm = obedit->data;
- EditBone *ebo, *eboflip;
-
- for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
- /* no layer check, correct mirror is more important */
- if (ebo->flag & (BONE_TIPSEL | BONE_ROOTSEL)) {
- eboflip = ED_armature_bone_get_mirrored(arm->edbo, ebo);
-
- if (eboflip) {
- /* we assume X-axis flipping for now */
- if (ebo->flag & BONE_TIPSEL) {
- EditBone *children;
-
- eboflip->tail[0] = -ebo->tail[0];
- eboflip->tail[1] = ebo->tail[1];
- eboflip->tail[2] = ebo->tail[2];
- eboflip->rad_tail = ebo->rad_tail;
- eboflip->roll = -ebo->roll;
-
- /* Also move connected children, in case children's name aren't mirrored properly */
- for (children = arm->edbo->first; children; children = children->next) {
- if (children->parent == eboflip && children->flag & BONE_CONNECTED) {
- copy_v3_v3(children->head, eboflip->tail);
- children->rad_head = ebo->rad_tail;
- }
- }
- }
- if (ebo->flag & BONE_ROOTSEL) {
- eboflip->head[0] = -ebo->head[0];
- eboflip->head[1] = ebo->head[1];
- eboflip->head[2] = ebo->head[2];
- eboflip->rad_head = ebo->rad_head;
- eboflip->roll = -ebo->roll;
-
- /* Also move connected parent, in case parent's name isn't mirrored properly */
- if (eboflip->parent && eboflip->flag & BONE_CONNECTED) {
- EditBone *parent = eboflip->parent;
- copy_v3_v3(parent->tail, eboflip->head);
- parent->rad_tail = ebo->rad_head;
- }
- }
- if (ebo->flag & BONE_SELECTED) {
- eboflip->dist = ebo->dist;
- eboflip->roll = -ebo->roll;
- eboflip->xwidth = ebo->xwidth;
- eboflip->zwidth = ebo->zwidth;
- }
- }
- }
- }
-}
-
-
-/*****************************************************************************************************/
-/*************************************** SKELETON GENERATOR ******************************************/
-/*****************************************************************************************************/
-
-#if 0
-
-/**************************************** SUBDIVISION ALGOS ******************************************/
-
-EditBone *subdivideByAngle(Scene *scene, Object *obedit, ReebArc *arc, ReebNode *head, ReebNode *tail)
-{
- bArmature *arm = obedit->data;
- EditBone *lastBone = NULL;
-
- if (scene->toolsettings->skgen_options & SKGEN_CUT_ANGLE) {
- ReebArcIterator arc_iter;
- BArcIterator *iter = (BArcIterator *)&arc_iter;
- float *previous = NULL, *current = NULL;
- EditBone *child = NULL;
- EditBone *parent = NULL;
- EditBone *root = NULL;
- float angleLimit = (float)cos(scene->toolsettings->skgen_angle_limit * M_PI / 180.0f);
-
- parent = ED_armature_edit_bone_add(arm, "Bone");
- parent->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
- copy_v3_v3(parent->head, head->p);
-
- root = parent;
-
- initArcIterator(iter, arc, head);
- IT_next(iter);
- previous = iter->p;
-
- for (IT_next(iter);
- IT_stopped(iter) == 0;
- previous = iter->p, IT_next(iter))
- {
- float vec1[3], vec2[3];
- float len1, len2;
-
- current = iter->p;
-
- sub_v3_v3v3(vec1, previous, parent->head);
- sub_v3_v3v3(vec2, current, previous);
-
- len1 = normalize_v3(vec1);
- len2 = normalize_v3(vec2);
-
- if (len1 > 0.0f && len2 > 0.0f && dot_v3v3(vec1, vec2) < angleLimit) {
- copy_v3_v3(parent->tail, previous);
-
- child = ED_armature_edit_bone_add(arm, "Bone");
- copy_v3_v3(child->head, parent->tail);
- child->parent = parent;
- child->flag |= BONE_CONNECTED | BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
-
- parent = child; /* new child is next parent */
- }
- }
- copy_v3_v3(parent->tail, tail->p);
-
- /* If the bone wasn't subdivided, delete it and return NULL
- * to let subsequent subdivision methods do their thing.
- * */
- if (parent == root) {
- if (parent == arm->act_edbone) arm->act_edbone = NULL;
- ED_armature_edit_bone_remove(arm, parent);
- parent = NULL;
- }
-
- lastBone = parent; /* set last bone in the chain */
- }
-
- return lastBone;
-}
-
-EditBone *test_subdivideByCorrelation(Scene *scene, Object *obedit, ReebArc *arc, ReebNode *head, ReebNode *tail)
-{
- EditBone *lastBone = NULL;
-
- if (scene->toolsettings->skgen_options & SKGEN_CUT_CORRELATION) {
- float invmat[4][4] = MAT4_UNITY;
- float tmat[3][3] = MAT3_UNITY;
- ReebArcIterator arc_iter;
- BArcIterator *iter = (BArcIterator *)&arc_iter;
- bArmature *arm = obedit->data;
-
- initArcIterator(iter, arc, head);
-
- lastBone = subdivideArcBy(arm, arm->edbo, iter, invmat, tmat, nextAdaptativeSubdivision);
- }
-
- return lastBone;
-}
-
-float arcLengthRatio(ReebArc *arc)
-{
- float arcLength = 0.0f;
- float embedLength = 0.0f;
- int i;
-
- arcLength = len_v3v3(arc->head->p, arc->tail->p);
-
- if (arc->bcount > 0) {
- /* Add the embedding */
- for (i = 1; i < arc->bcount; i++) {
- embedLength += len_v3v3(arc->buckets[i - 1].p, arc->buckets[i].p);
- }
- /* Add head and tail -> embedding vectors */
- embedLength += len_v3v3(arc->head->p, arc->buckets[0].p);
- embedLength += len_v3v3(arc->tail->p, arc->buckets[arc->bcount - 1].p);
- }
- else {
- embedLength = arcLength;
- }
-
- return embedLength / arcLength;
-}
-
-EditBone *test_subdivideByLength(Scene *scene, Object *obedit, ReebArc *arc, ReebNode *head, ReebNode *tail)
-{
- EditBone *lastBone = NULL;
- if ((scene->toolsettings->skgen_options & SKGEN_CUT_LENGTH) &&
- arcLengthRatio(arc) >= G.scene->toolsettings->skgen_length_ratio)
- {
- float invmat[4][4] = MAT4_UNITY;
- float tmat[3][3] = MAT3_UNITY;
- ReebArcIterator arc_iter;
- BArcIterator *iter = (BArcIterator *)&arc_iter;
- bArmature *arm = obedit->data;
-
- initArcIterator(iter, arc, head);
-
- lastBone = subdivideArcBy(arm, arm->edbo, iter, invmat, tmat, nextLengthSubdivision);
- }
-
- return lastBone;
-}
-
-/***************************************** MAIN ALGORITHM ********************************************/
-
-void generateSkeletonFromReebGraph(Scene *scene, ReebGraph *rg)
-{
- Object *obedit = scene->obedit; // XXX get from context
- GHash *arcBoneMap = NULL;
- ReebArc *arc = NULL;
- ReebNode *node = NULL;
- Object *src = NULL;
- Object *dst = NULL;
-
- src = scene->basact->object;
-
- if (obedit != NULL) {
- ED_armature_from_edit(obedit);
- ED_armature_edit_free(obedit);
- }
-
- dst = BKE_object_add(scene, OB_ARMATURE);
- ED_object_base_init_transform(NULL, scene->basact, NULL, NULL); // XXX NULL is C, loc, rot
- obedit = scene->basact->object;
-
- /* Copy orientation from source */
- copy_v3_v3(dst->loc, src->obmat[3]);
- mat4_to_eul(dst->rot, src->obmat);
- mat4_to_size(dst->size, src->obmat);
-
- BKE_object_where_is_calc(scene, obedit);
-
- ED_armature_to_edit(obedit);
-
- arcBoneMap = BLI_ghash_ptr_new("SkeletonFromReebGraph gh");
-
- BLI_markdownSymmetry((BGraph *)rg, rg->nodes.first, scene->toolsettings->skgen_symmetry_limit);
-
- for (arc = rg->arcs.first; arc; arc = arc->next)
- {
- EditBone *lastBone = NULL;
- ReebNode *head, *tail;
- int i;
-
- /* Find out the direction of the arc through simple heuristics (in order of priority) :
- *
- * 1- Arcs on primary symmetry axis (symmetry == 1) point up (head: high weight -> tail: low weight)
- * 2- Arcs starting on a primary axis point away from it (head: node on primary axis)
- * 3- Arcs point down (head: low weight -> tail: high weight)
- *
- * Finally, the arc direction is stored in its flag: 1 (low -> high), -1 (high -> low)
- */
-
- /* if arc is a symmetry axis, internal bones go up the tree */
- if (arc->symmetry_level == 1 && arc->tail->degree != 1) {
- head = arc->tail;
- tail = arc->head;
-
- arc->flag = -1; /* mark arc direction */
- }
- /* Bones point AWAY from the symmetry axis */
- else if (arc->head->symmetry_level == 1) {
- head = arc->head;
- tail = arc->tail;
-
- arc->flag = 1; /* mark arc direction */
- }
- else if (arc->tail->symmetry_level == 1) {
- head = arc->tail;
- tail = arc->head;
-
- arc->flag = -1; /* mark arc direction */
- }
- /* otherwise, always go from low weight to high weight */
- else {
- head = arc->head;
- tail = arc->tail;
-
- arc->flag = 1; /* mark arc direction */
- }
-
- /* Loop over subdivision methods */
- for (i = 0; lastBone == NULL && i < SKGEN_SUB_TOTAL; i++) {
- switch (scene->toolsettings->skgen_subdivisions[i]) {
- case SKGEN_SUB_LENGTH:
- lastBone = test_subdivideByLength(scene, obedit, arc, head, tail);
- break;
- case SKGEN_SUB_ANGLE:
- lastBone = subdivideByAngle(scene, obedit, arc, head, tail);
- break;
- case SKGEN_SUB_CORRELATION:
- lastBone = test_subdivideByCorrelation(scene, obedit, arc, head, tail);
- break;
- }
- }
-
- if (lastBone == NULL) {
- EditBone *bone;
- bone = ED_armature_edit_bone_add(obedit->data, "Bone");
- bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
-
- copy_v3_v3(bone->head, head->p);
- copy_v3_v3(bone->tail, tail->p);
-
- /* set first and last bone, since there's only one */
- lastBone = bone;
- }
-
- BLI_ghash_insert(arcBoneMap, arc, lastBone);
- }
-
- /* Second pass, setup parent relationship between arcs */
- for (node = rg->nodes.first; node; node = node->next)
- {
- ReebArc *incomingArc = NULL;
- int i;
-
- for (i = 0; i < node->degree; i++) {
- arc = (ReebArc *)node->arcs[i];
-
- /* if arc is incoming into the node */
- if ((arc->head == node && arc->flag == -1) ||
- (arc->tail == node && arc->flag == 1))
- {
- if (incomingArc == NULL) {
- incomingArc = arc;
- /* loop further to make sure there's only one incoming arc */
- }
- else {
- /* skip this node if more than one incomingArc */
- incomingArc = NULL;
- break; /* No need to look further, we are skipping already */
- }
- }
- }
-
- if (incomingArc != NULL) {
- EditBone *parentBone = BLI_ghash_lookup(arcBoneMap, incomingArc);
-
- /* Look for outgoing arcs and parent their bones */
- for (i = 0; i < node->degree; i++)
- {
- arc = node->arcs[i];
-
- /* if arc is outgoing from the node */
- if ((arc->head == node && arc->flag == 1) || (arc->tail == node && arc->flag == -1)) {
- EditBone *childBone = BLI_ghash_lookup(arcBoneMap, arc);
-
- /* find the root bone */
- while (childBone->parent != NULL)
- {
- childBone = childBone->parent;
- }
-
- childBone->parent = parentBone;
- childBone->flag |= BONE_CONNECTED;
- }
- }
- }
- }
-
- BLI_ghash_free(arcBoneMap, NULL, NULL);
-}
-
-void generateSkeleton(Scene *scene)
-{
- ReebGraph *reebg;
-
-// setcursor_space(SPACE_VIEW3D, CURSOR_WAIT);
-
- reebg = BIF_ReebGraphFromEditMesh();
-
- generateSkeletonFromReebGraph(scene, reebg);
-
- REEB_freeGraph(reebg);
-
- //setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
-}
-
-#endif
diff --git a/source/blender/editors/armature/editarmature_generate.c b/source/blender/editors/armature/editarmature_generate.c
index 979c352c4b2..89772d38e8f 100644
--- a/source/blender/editors/armature/editarmature_generate.c
+++ b/source/blender/editors/armature/editarmature_generate.c
@@ -30,24 +30,13 @@
* \ingroup edarmature
*/
-
-#include <string.h>
-#include <math.h>
-#include <float.h>
-
-
#include "DNA_scene_types.h"
#include "DNA_armature_types.h"
-#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_graph.h"
-#include "BLI_utildefines.h"
-
-
#include "ED_armature.h"
-#include "armature_intern.h"
#include "BIF_generate.h"
void setBoneRollFromNormal(EditBone *bone, const float no[3], float UNUSED(invmat[4][4]), float tmat[3][3])
diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c
index 3e34a4c6808..62cce6b2c1e 100644
--- a/source/blender/editors/armature/editarmature_retarget.c
+++ b/source/blender/editors/armature/editarmature_retarget.c
@@ -25,12 +25,6 @@
* \ingroup edarmature
*/
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <float.h>
-
#include "MEM_guardedalloc.h"
#include "PIL_time.h"
@@ -42,11 +36,6 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
-#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
-#include "BLI_graph.h"
-#include "BLI_rand.h"
-#include "BLI_threads.h"
#include "BKE_constraint.h"
#include "BKE_armature.h"
@@ -57,8 +46,6 @@
#include "BIF_retarget.h"
-#include "reeb.h" /* FIX ME */
-
#include "armature_intern.h"
/************ RIG RETARGET DATA STRUCTURES ***************/
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index b61aa86a52f..ec96c574f75 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -22,10 +22,6 @@
* \ingroup edarmature
*/
-#include <string.h>
-#include <math.h>
-#include <float.h>
-
#include "MEM_guardedalloc.h"
#include "DNA_object_types.h"
@@ -37,9 +33,6 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
-#include "BLI_utildefines.h"
-#include "BLI_graph.h"
-#include "BLI_ghash.h"
#include "BLF_translation.h"
@@ -60,8 +53,6 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "reeb.h"
-
typedef int (*GestureDetectFct)(bContext *, SK_Gesture *, SK_Sketch *);
typedef void (*GestureApplyFct)(bContext *, SK_Gesture *, SK_Sketch *);
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index a7e84d590b5..3ac514f1465 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -30,18 +30,12 @@
* \ingroup edarmature
*/
-
-#include <math.h>
-#include <string.h>
-
#include "MEM_guardedalloc.h"
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
-#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_edgehash.h"
#include "BLI_memarena.h"
@@ -59,8 +53,6 @@
#include "ONL_opennl.h"
-#include "BLO_sys_types.h" // for intptr_t support
-
#include "ED_mesh.h"
#include "ED_armature.h"
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
new file mode 100644
index 00000000000..3d1d5d2f6ba
--- /dev/null
+++ b/source/blender/editors/armature/pose_edit.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.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Ton Roosendaal, Blender Foundation '05, full recode.
+ * Joshua Leung
+ * Reevan McKay (original NaN code)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Pose Mode API's and Operators for Pose Mode armatures
+ */
+
+/** \file blender/editors/armature/pose_edit.c
+ * \ingroup edarmature
+ */
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_anim.h"
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_keyframing.h"
+#include "ED_screen.h"
+#include "ED_object.h"
+
+#include "UI_interface.h"
+
+#include "armature_intern.h"
+
+/* matches logic with ED_operator_posemode_context() */
+Object *ED_pose_object_from_context(bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ Object *ob;
+
+ /* since this call may also be used from the buttons window, we need to check for where to get the object */
+ if (sa && sa->spacetype == SPACE_BUTS) {
+ ob = ED_object_context(C);
+ }
+ else {
+ ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ }
+
+ return ob;
+}
+
+/* This function is used to process the necessary updates for */
+void ED_armature_enter_posemode(bContext *C, Base *base)
+{
+ ReportList *reports = CTX_wm_reports(C);
+ Object *ob = base->object;
+
+ if (ob->id.lib) {
+ BKE_report(reports, RPT_WARNING, "Cannot pose libdata");
+ return;
+ }
+
+ switch (ob->type) {
+ case OB_ARMATURE:
+ ob->restore_mode = ob->mode;
+ ob->mode |= OB_MODE_POSE;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL);
+
+ break;
+ default:
+ return;
+ }
+
+ /* XXX: disabled as this would otherwise cause a nasty loop... */
+ //ED_object_toggle_modes(C, ob->mode);
+}
+
+void ED_armature_exit_posemode(bContext *C, Base *base)
+{
+ if (base) {
+ Object *ob = base->object;
+
+ ob->restore_mode = ob->mode;
+ ob->mode &= ~OB_MODE_POSE;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
+ }
+}
+
+/* if a selected or active bone is protected, throw error (oonly if warn == 1) and return 1 */
+/* only_selected == 1: the active bone is allowed to be protected */
+#if 0 /* UNUSED 2.5 */
+static short pose_has_protected_selected(Object *ob, short warn)
+{
+ /* check protection */
+ if (ob->proxy) {
+ bPoseChannel *pchan;
+ bArmature *arm = ob->data;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone && (pchan->bone->layer & arm->layer)) {
+ if (pchan->bone->layer & arm->layer_protected) {
+ if (pchan->bone->flag & BONE_SELECTED)
+ break;
+ }
+ }
+ }
+ if (pchan) {
+ if (warn) error("Cannot change Proxy protected bones");
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif
+
+/* only for real IK, not for auto-IK */
+static int pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan, int level)
+{
+ bConstraint *con;
+ Bone *bone;
+
+ /* No need to check if constraint is active (has influence),
+ * since all constraints with CONSTRAINT_IK_AUTO are active */
+ for (con = pchan->constraints.first; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ bKinematicConstraint *data = con->data;
+ if (data->rootbone == 0 || data->rootbone > level) {
+ if ((data->flag & CONSTRAINT_IK_AUTO) == 0)
+ return 1;
+ }
+ }
+ }
+ for (bone = pchan->bone->childbase.first; bone; bone = bone->next) {
+ pchan = BKE_pose_channel_find_name(ob->pose, bone->name);
+ if (pchan && pose_channel_in_IK_chain(ob, pchan, level + 1))
+ return 1;
+ }
+ return 0;
+}
+
+int ED_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan)
+{
+ return pose_channel_in_IK_chain(ob, pchan, 0);
+}
+
+/* ********************************************** */
+/* Motion Paths */
+
+/* For the object with pose/action: update paths for those that have got them
+ * This should selectively update paths that exist...
+ *
+ * To be called from various tools that do incremental updates
+ */
+void ED_pose_recalculate_paths(Scene *scene, Object *ob)
+{
+ ListBase targets = {NULL, NULL};
+
+ /* set flag to force recalc, then grab the relevant bones to target */
+ ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS;
+ animviz_get_object_motionpaths(ob, &targets);
+
+ /* recalculate paths, then free */
+ animviz_calc_motionpaths(scene, &targets);
+ BLI_freelistN(&targets);
+}
+
+
+/* show popup to determine settings */
+static int pose_calculate_paths_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ /* set default settings from existing/stored settings */
+ {
+ bAnimVizSettings *avs = &ob->pose->avs;
+ PointerRNA avs_ptr;
+
+ RNA_int_set(op->ptr, "start_frame", avs->path_sf);
+ RNA_int_set(op->ptr, "end_frame", avs->path_ef);
+
+ RNA_pointer_create(NULL, &RNA_AnimVizMotionPaths, avs, &avs_ptr);
+ RNA_enum_set(op->ptr, "bake_location", RNA_enum_get(&avs_ptr, "bake_location"));
+ }
+
+ /* show popup dialog to allow editing of range... */
+ // FIXME: hardcoded dimensions here are just arbitrary
+ return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 10 * UI_UNIT_Y);
+}
+
+/* For the object with pose/action: create path curves for selected bones
+ * This recalculates the WHOLE path within the pchan->pathsf and pchan->pathef range
+ */
+static int pose_calculate_paths_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ Scene *scene = CTX_data_scene(C);
+
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ /* grab baking settings from operator settings */
+ {
+ bAnimVizSettings *avs = &ob->pose->avs;
+ PointerRNA avs_ptr;
+
+ avs->path_sf = RNA_int_get(op->ptr, "start_frame");
+ avs->path_ef = RNA_int_get(op->ptr, "end_frame");
+
+ RNA_pointer_create(NULL, &RNA_AnimVizMotionPaths, avs, &avs_ptr);
+ RNA_enum_set(&avs_ptr, "bake_location", RNA_enum_get(op->ptr, "bake_location"));
+ }
+
+ /* set up path data for bones being calculated */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ /* verify makes sure that the selected bone has a bone with the appropriate settings */
+ animviz_verify_motionpaths(op->reports, scene, ob, pchan);
+ }
+ CTX_DATA_END;
+
+ /* calculate the bones that now have motionpaths... */
+ /* TODO: only make for the selected bones? */
+ ED_pose_recalculate_paths(scene, ob);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_paths_calculate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Calculate Bone Paths";
+ ot->idname = "POSE_OT_paths_calculate";
+ ot->description = "Calculate paths for the selected bones";
+
+ /* api callbacks */
+ ot->invoke = pose_calculate_paths_invoke;
+ ot->exec = pose_calculate_paths_exec;
+ ot->poll = ED_operator_posemode_exclusive;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_int(ot->srna, "start_frame", 1, MINAFRAME, MAXFRAME, "Start",
+ "First frame to calculate bone paths on", MINFRAME, MAXFRAME / 2.0);
+ 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,
+ "Bake Location",
+ "Which point on the bones is used when calculating paths");
+}
+
+/* --------- */
+
+static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ Scene *scene = CTX_data_scene(C);
+
+ if (ELEM(NULL, ob, scene))
+ return OPERATOR_CANCELLED;
+
+ /* calculate the bones that now have motionpaths... */
+ /* TODO: only make for the selected bones? */
+ ED_pose_recalculate_paths(scene, ob);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_paths_update(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Update Bone Paths";
+ ot->idname = "POSE_OT_paths_update";
+ ot->description = "Recalculate paths for bones that already have them";
+
+ /* 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 */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* --------- */
+
+/* for the object with pose/action: clear path curves for selected bones only */
+static void ED_pose_clear_paths(Object *ob)
+{
+ bPoseChannel *pchan;
+ short skipped = 0;
+
+ if (ELEM(NULL, ob, ob->pose))
+ return;
+
+ /* free the motionpath blocks, but also take note of whether we skipped some... */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->mpath) {
+ if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
+ animviz_free_motionpath(pchan->mpath);
+ pchan->mpath = NULL;
+ }
+ else
+ skipped = 1;
+ }
+ }
+
+ /* if we didn't skip any, we shouldn't have any paths left */
+ if (skipped == 0)
+ ob->pose->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS;
+}
+
+/* operator callback for this */
+static int pose_clear_paths_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+
+ /* 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);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+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";
+
+ /* api callbacks */
+ ot->exec = pose_clear_paths_exec;
+ ot->poll = ED_operator_posemode_exclusive;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************************** */
+#if 0 /* UNUSED 2.5 */
+static void pose_copy_menu(Scene *scene)
+{
+ Object *obedit = scene->obedit; // XXX context
+ Object *ob = OBACT;
+ bArmature *arm;
+ bPoseChannel *pchan, *pchanact;
+ short nr = 0;
+ int i = 0;
+
+ /* paranoia checks */
+ if (ELEM(NULL, ob, ob->pose)) return;
+ if ((ob == obedit) || (ob->mode & OB_MODE_POSE) == 0) return;
+
+ pchan = BKE_pose_channel_active(ob);
+
+ if (pchan == NULL) return;
+ pchanact = pchan;
+ arm = ob->data;
+
+ /* if proxy-protected bones selected, some things (such as locks + displays) shouldn't be changeable,
+ * but for constraints (just add local constraints)
+ */
+ if (pose_has_protected_selected(ob, 0)) {
+ i = BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
+ if (i < 25)
+ nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|Constraints... %x5");
+ else
+ nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4");
+ }
+ else {
+ i = BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
+ if (i < 25)
+ nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|Constraints... %x5|%l|Transform Locks %x6|IK Limits %x7|Bone Shape %x8");
+ else
+ nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|%l|Transform Locks %x6|IK Limits %x7|Bone Shape %x8");
+ }
+
+ if (nr <= 0)
+ return;
+
+ if (nr != 5) {
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((arm->layer & pchan->bone->layer) &&
+ (pchan->bone->flag & BONE_SELECTED) &&
+ (pchan != pchanact) )
+ {
+ switch (nr) {
+ case 1: /* Local Location */
+ copy_v3_v3(pchan->loc, pchanact->loc);
+ break;
+ case 2: /* Local Rotation */
+ copy_qt_qt(pchan->quat, pchanact->quat);
+ copy_v3_v3(pchan->eul, pchanact->eul);
+ break;
+ case 3: /* Local Size */
+ copy_v3_v3(pchan->size, pchanact->size);
+ break;
+ case 4: /* All Constraints */
+ {
+ ListBase tmp_constraints = {NULL, NULL};
+
+ /* copy constraints to tmpbase and apply 'local' tags before
+ * appending to list of constraints for this channel
+ */
+ BKE_copy_constraints(&tmp_constraints, &pchanact->constraints, TRUE);
+ if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) {
+ bConstraint *con;
+
+ /* add proxy-local tags */
+ for (con = tmp_constraints.first; con; con = con->next)
+ con->flag |= CONSTRAINT_PROXY_LOCAL;
+ }
+ BLI_movelisttolist(&pchan->constraints, &tmp_constraints);
+
+ /* update flags (need to add here, not just copy) */
+ pchan->constflag |= pchanact->constflag;
+
+ if (ob->pose)
+ ob->pose->flag |= POSE_RECALC;
+ }
+ break;
+ case 6: /* Transform Locks */
+ pchan->protectflag = pchanact->protectflag;
+ break;
+ case 7: /* IK (DOF) settings */
+ {
+ pchan->ikflag = pchanact->ikflag;
+ copy_v3_v3(pchan->limitmin, pchanact->limitmin);
+ copy_v3_v3(pchan->limitmax, pchanact->limitmax);
+ copy_v3_v3(pchan->stiffness, pchanact->stiffness);
+ pchan->ikstretch = pchanact->ikstretch;
+ pchan->ikrotweight = pchanact->ikrotweight;
+ pchan->iklinweight = pchanact->iklinweight;
+ }
+ break;
+ case 8: /* Custom Bone Shape */
+ pchan->custom = pchanact->custom;
+ break;
+ case 9: /* Visual Location */
+ BKE_armature_loc_pose_to_bone(pchan, pchanact->pose_mat[3], pchan->loc);
+ break;
+ case 10: /* Visual Rotation */
+ {
+ float delta_mat[4][4];
+
+ BKE_armature_mat_pose_to_bone(pchan, pchanact->pose_mat, delta_mat);
+
+ if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ float tmp_quat[4];
+
+ /* need to convert to quat first (in temp var)... */
+ mat4_to_quat(tmp_quat, delta_mat);
+ quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, tmp_quat);
+ }
+ else if (pchan->rotmode == ROT_MODE_QUAT)
+ mat4_to_quat(pchan->quat, delta_mat);
+ else
+ mat4_to_eulO(pchan->eul, pchan->rotmode, delta_mat);
+ }
+ break;
+ case 11: /* Visual Size */
+ {
+ float delta_mat[4][4], size[4];
+
+ BKE_armature_mat_pose_to_bone(pchan, pchanact->pose_mat, delta_mat);
+ mat4_to_size(size, delta_mat);
+ copy_v3_v3(pchan->size, size);
+ }
+ }
+ }
+ }
+ }
+ else { /* constraints, optional (note: max we can have is 24 constraints) */
+ bConstraint *con, *con_back;
+ int const_toggle[24] = {0}; /* XXX, initialize as 0 to quiet errors */
+ ListBase const_copy = {NULL, NULL};
+
+ BLI_duplicatelist(&const_copy, &(pchanact->constraints));
+
+ /* build the puplist of constraints */
+ for (con = pchanact->constraints.first, i = 0; con; con = con->next, i++) {
+ const_toggle[i] = 1;
+// add_numbut(i, TOG|INT, con->name, 0, 0, &(const_toggle[i]), "");
+ }
+
+// if (!do_clever_numbuts("Select Constraints", i, REDRAW)) {
+// BLI_freelistN(&const_copy);
+// return;
+// }
+
+ /* now build a new listbase from the options selected */
+ for (i = 0, con = const_copy.first; con; i++) {
+ /* if not selected, free/remove it from the list */
+ if (!const_toggle[i]) {
+ con_back = con->next;
+ BLI_freelinkN(&const_copy, con);
+ con = con_back;
+ }
+ else
+ con = con->next;
+ }
+
+ /* Copy the temo listbase to the selected posebones */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((arm->layer & pchan->bone->layer) &&
+ (pchan->bone->flag & BONE_SELECTED) &&
+ (pchan != pchanact) )
+ {
+ ListBase tmp_constraints = {NULL, NULL};
+
+ /* copy constraints to tmpbase and apply 'local' tags before
+ * appending to list of constraints for this channel
+ */
+ BKE_copy_constraints(&tmp_constraints, &const_copy, TRUE);
+ if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) {
+ /* add proxy-local tags */
+ for (con = tmp_constraints.first; con; con = con->next)
+ con->flag |= CONSTRAINT_PROXY_LOCAL;
+ }
+ BLI_movelisttolist(&pchan->constraints, &tmp_constraints);
+
+ /* update flags (need to add here, not just copy) */
+ pchan->constflag |= pchanact->constflag;
+ }
+ }
+ BLI_freelistN(&const_copy);
+ BKE_pose_update_constraint_flags(ob->pose); /* we could work out the flags but its simpler to do this */
+
+ if (ob->pose)
+ ob->pose->flag |= POSE_RECALC;
+ }
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations
+
+ BIF_undo_push("Copy Pose Attributes");
+
+}
+#endif
+
+/* ********************************************** */
+
+static int pose_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm;
+
+ /* paranoia checks */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+ arm = ob->data;
+
+ /* loop through selected bones, auto-naming them */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ char newname[MAXBONENAME];
+ flip_side_name(newname, pchan->name, TRUE);
+ ED_armature_bone_rename(arm, pchan->name, newname);
+ }
+ CTX_DATA_END;
+
+ /* since we renamed stuff... */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_flip_names(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Flip Names";
+ ot->idname = "POSE_OT_flip_names";
+ ot->description = "Flips (and corrects) the axis suffixes of the the names of selected bones";
+
+ /* api callbacks */
+ ot->exec = pose_flip_names_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ------------------ */
+
+static int pose_autoside_names_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm;
+ char newname[MAXBONENAME];
+ short axis = RNA_enum_get(op->ptr, "axis");
+
+ /* paranoia checks */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+ arm = ob->data;
+
+ /* loop through selected bones, auto-naming them */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ BLI_strncpy(newname, pchan->name, sizeof(newname));
+ if (bone_autoside_name(newname, 1, axis, pchan->bone->head[axis], pchan->bone->tail[axis]))
+ ED_armature_bone_rename(arm, pchan->name, newname);
+ }
+ CTX_DATA_END;
+
+ /* since we renamed stuff... */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_autoside_names(wmOperatorType *ot)
+{
+ static EnumPropertyItem axis_items[] = {
+ {0, "XAXIS", 0, "X-Axis", "Left/Right"},
+ {1, "YAXIS", 0, "Y-Axis", "Front/Back"},
+ {2, "ZAXIS", 0, "Z-Axis", "Top/Bottom"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "AutoName by Axis";
+ ot->idname = "POSE_OT_autoside_names";
+ ot->description = "Automatically renames the selected bones according to which side of the target axis they fall on";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = pose_autoside_names_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* settings */
+ ot->prop = RNA_def_enum(ot->srna, "axis", axis_items, 0, "Axis", "Axis tag names with");
+}
+
+/* ********************************************** */
+
+static int pose_bone_rotmode_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ int mode = RNA_enum_get(op->ptr, "type");
+
+ /* set rotation mode of selected bones */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ pchan->rotmode = mode;
+ }
+ CTX_DATA_END;
+
+ /* notifiers and updates */
+ DAG_id_tag_update((ID *)ob, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_rotation_mode_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Rotation Mode";
+ ot->idname = "POSE_OT_rotation_mode_set";
+ ot->description = "Set the rotation representation used by selected bones";
+
+ /* callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = pose_bone_rotmode_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", posebone_rotmode_items, 0, "Rotation Mode", "");
+}
+
+/* ********************************************** */
+
+/* Show all armature layers */
+static int pose_armature_layers_showall_poll(bContext *C)
+{
+ /* this single operator can be used in posemode OR editmode for armatures */
+ return ED_operator_posemode(C) || ED_operator_editarmature(C);
+}
+
+static int pose_armature_layers_showall_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = (ob) ? ob->data : NULL;
+ PointerRNA ptr;
+ int maxLayers = (RNA_boolean_get(op->ptr, "all")) ? 32 : 16;
+ int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+ int i;
+
+ /* sanity checking */
+ if (arm == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* use RNA to set the layers
+ * although it would be faster to just set directly using bitflags, we still
+ * need to setup a RNA pointer so that we get the "update" callbacks for free...
+ */
+ RNA_id_pointer_create(&arm->id, &ptr);
+
+ for (i = 0; i < maxLayers; i++)
+ layers[i] = 1;
+
+ RNA_boolean_set_array(&ptr, "layers", layers);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ /* done */
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_layers_show_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Show All Layers";
+ ot->idname = "ARMATURE_OT_layers_show_all";
+ ot->description = "Make all armature layers visible";
+
+ /* callbacks */
+ ot->exec = pose_armature_layers_showall_exec;
+ ot->poll = pose_armature_layers_showall_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All Layers", "Enable all layers or just the first 16 (top row)");
+}
+
+/* ------------------- */
+
+/* Present a popup to get the layers that should be used */
+static int pose_armature_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = (ob) ? ob->data : NULL;
+ PointerRNA ptr;
+ int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+
+ /* sanity checking */
+ if (arm == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* get RNA pointer to armature data to use that to retrieve the layers as ints to init the operator */
+ RNA_id_pointer_create((ID *)arm, &ptr);
+ RNA_boolean_get_array(&ptr, "layers", layers);
+ RNA_boolean_set_array(op->ptr, "layers", layers);
+
+ /* part to sync with other similar operators... */
+ return WM_operator_props_popup(C, op, evt);
+}
+
+/* Set the visible layers for the active armature (edit and pose modes) */
+static int pose_armature_layers_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ PointerRNA ptr;
+ int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+
+ if (ELEM(NULL, ob, ob->data)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* get the values set in the operator properties */
+ RNA_boolean_get_array(op->ptr, "layers", layers);
+
+ /* get pointer for armature, and write data there... */
+ RNA_id_pointer_create((ID *)ob->data, &ptr);
+ RNA_boolean_set_array(&ptr, "layers", layers);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+
+void POSE_OT_armature_layers(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Change Armature Layers";
+ ot->idname = "POSE_OT_armature_layers";
+ ot->description = "Change the visible armature layers";
+
+ /* callbacks */
+ ot->invoke = pose_armature_layers_invoke;
+ ot->exec = pose_armature_layers_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers to make visible");
+}
+
+void ARMATURE_OT_armature_layers(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Change Armature Layers";
+ ot->idname = "ARMATURE_OT_armature_layers";
+ ot->description = "Change the visible armature layers";
+
+ /* callbacks */
+ ot->invoke = pose_armature_layers_invoke;
+ ot->exec = pose_armature_layers_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers to make visible");
+}
+
+/* ------------------- */
+
+/* Present a popup to get the layers that should be used */
+static int pose_bone_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+{
+ int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+
+ /* get layers that are active already */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ short bit;
+
+ /* loop over the bits for this pchan's layers, adding layers where they're needed */
+ for (bit = 0; bit < 32; bit++) {
+ if (pchan->bone->layer & (1 << bit))
+ layers[bit] = 1;
+ }
+ }
+ CTX_DATA_END;
+
+ /* copy layers to operator */
+ RNA_boolean_set_array(op->ptr, "layers", layers);
+
+ /* part to sync with other similar operators... */
+ return WM_operator_props_popup(C, op, evt);
+}
+
+/* Set the visible layers for the active armature (edit and pose modes) */
+static int pose_bone_layers_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ PointerRNA ptr;
+ int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+
+ if (ob == NULL || ob->data == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* get the values set in the operator properties */
+ RNA_boolean_get_array(op->ptr, "layers", layers);
+
+ /* set layers of pchans based on the values set in the operator props */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ /* get pointer for pchan, and write flags this way */
+ RNA_pointer_create((ID *)ob->data, &RNA_Bone, pchan->bone, &ptr);
+ RNA_boolean_set_array(&ptr, "layers", layers);
+ }
+ CTX_DATA_END;
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_bone_layers(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Change Bone Layers";
+ ot->idname = "POSE_OT_bone_layers";
+ ot->description = "Change the layers that the selected bones belong to";
+
+ /* callbacks */
+ ot->invoke = pose_bone_layers_invoke;
+ ot->exec = pose_bone_layers_exec;
+ ot->poll = ED_operator_posemode_exclusive;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to");
+}
+
+/* ------------------- */
+
+/* Present a popup to get the layers that should be used */
+static int armature_bone_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+{
+ int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+
+ /* get layers that are active already */
+ CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones)
+ {
+ short bit;
+
+ /* loop over the bits for this pchan's layers, adding layers where they're needed */
+ for (bit = 0; bit < 32; bit++) {
+ if (ebone->layer & (1 << bit))
+ layers[bit] = 1;
+ }
+ }
+ CTX_DATA_END;
+
+ /* copy layers to operator */
+ RNA_boolean_set_array(op->ptr, "layers", layers);
+
+ /* part to sync with other similar operators... */
+ return WM_operator_props_popup(C, op, evt);
+}
+
+/* Set the visible layers for the active armature (edit and pose modes) */
+static int armature_bone_layers_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ bArmature *arm = (ob) ? ob->data : NULL;
+ PointerRNA ptr;
+ int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+
+ /* get the values set in the operator properties */
+ RNA_boolean_get_array(op->ptr, "layers", layers);
+
+ /* set layers of pchans based on the values set in the operator props */
+ CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones)
+ {
+ /* get pointer for pchan, and write flags this way */
+ RNA_pointer_create((ID *)arm, &RNA_EditBone, ebone, &ptr);
+ RNA_boolean_set_array(&ptr, "layers", layers);
+ }
+ CTX_DATA_END;
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void ARMATURE_OT_bone_layers(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Change Bone Layers";
+ ot->idname = "ARMATURE_OT_bone_layers";
+ ot->description = "Change the layers that the selected bones belong to";
+
+ /* callbacks */
+ ot->invoke = armature_bone_layers_invoke;
+ ot->exec = armature_bone_layers_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to");
+}
+
+/* ********************************************** */
+/* Show/Hide Bones */
+
+static int hide_selected_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
+{
+ bArmature *arm = ob->data;
+
+ if (arm->layer & bone->layer) {
+ if (bone->flag & BONE_SELECTED) {
+ bone->flag |= BONE_HIDDEN_P;
+ bone->flag &= ~BONE_SELECTED;
+ if (arm->act_bone == bone)
+ arm->act_bone = NULL;
+ }
+ }
+ return 0;
+}
+
+static int hide_unselected_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
+{
+ bArmature *arm = ob->data;
+
+ if (arm->layer & bone->layer) {
+ /* hrm... typo here? */
+ if ((bone->flag & BONE_SELECTED) == 0) {
+ bone->flag |= BONE_HIDDEN_P;
+ if (arm->act_bone == bone)
+ arm->act_bone = NULL;
+ }
+ }
+ return 0;
+}
+
+/* active object is armature in posemode, poll checked */
+static int pose_hide_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = ob->data;
+
+ if (RNA_boolean_get(op->ptr, "unselected"))
+ bone_looper(ob, arm->bonebase.first, NULL, hide_unselected_pose_bone_cb);
+ else
+ bone_looper(ob, arm->bonebase.first, NULL, hide_selected_pose_bone_cb);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_hide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Hide Selected";
+ ot->idname = "POSE_OT_hide";
+ ot->description = "Tag selected bones to not be visible in Pose Mode";
+
+ /* api callbacks */
+ ot->exec = pose_hide_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "");
+}
+
+static int show_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
+{
+ bArmature *arm = ob->data;
+
+ if (arm->layer & bone->layer) {
+ if (bone->flag & BONE_HIDDEN_P) {
+ bone->flag &= ~BONE_HIDDEN_P;
+ bone->flag |= BONE_SELECTED;
+ }
+ }
+
+ return 0;
+}
+
+/* active object is armature in posemode, poll checked */
+static int pose_reveal_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = ob->data;
+
+ bone_looper(ob, arm->bonebase.first, NULL, show_pose_bone_cb);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_reveal(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Reveal Selected";
+ ot->idname = "POSE_OT_reveal";
+ ot->description = "Unhide all bones that have been tagged to be hidden in Pose Mode";
+
+ /* api callbacks */
+ ot->exec = pose_reveal_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************************** */
+/* Flip Quats */
+
+static int pose_flip_quats_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
+
+ /* loop through all selected pchans, flipping and keying (as needed) */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ /* only if bone is using quaternion rotation */
+ if (pchan->rotmode == ROT_MODE_QUAT) {
+ /* quaternions have 720 degree range */
+ negate_v4(pchan->quat);
+
+ ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers and updates */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_quaternions_flip(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Flip Quats";
+ ot->idname = "POSE_OT_quaternions_flip";
+ ot->description = "Flip quaternion values to achieve desired rotations, while maintaining the same orientations";
+
+ /* callbacks */
+ ot->exec = pose_flip_quats_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
new file mode 100644
index 00000000000..06a88f013d7
--- /dev/null
+++ b/source/blender/editors/armature/pose_group.c
@@ -0,0 +1,523 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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) 2008 Blender Foundation
+ * All rights reserved.
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Implementation of Bone Groups operators and editing API's
+ */
+
+/** \file blender/editors/armature/pose_group.c
+ * \ingroup edarmature
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_action.h"
+#include "BKE_context.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "armature_intern.h"
+
+/* ********************************************** */
+/* Bone Groups */
+
+static int pose_group_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_pose_object_from_context(C);
+
+ /* only continue if there's an object */
+ if (ob == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* for now, just call the API function for this */
+ BKE_pose_add_group(ob);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_group_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Bone Group";
+ ot->idname = "POSE_OT_group_add";
+ ot->description = "Add a new bone group";
+
+ /* api callbacks */
+ ot->exec = pose_group_add_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int pose_group_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_pose_object_from_context(C);
+
+ /* only continue if there's an object */
+ if (ob == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* for now, just call the API function for this */
+ BKE_pose_remove_group(ob);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_group_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Bone Group";
+ ot->idname = "POSE_OT_group_remove";
+ ot->description = "Remove the active bone group";
+
+ /* api callbacks */
+ ot->exec = pose_group_remove_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ------------ */
+
+/* invoke callback which presents a list of bone-groups for the user to choose from */
+static int pose_groups_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
+{
+ Object *ob = ED_pose_object_from_context(C);
+ bPose *pose;
+
+ uiPopupMenu *pup;
+ uiLayout *layout;
+ bActionGroup *grp;
+ int i;
+
+ /* only continue if there's an object, and a pose there too */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+ pose = ob->pose;
+
+ /* if there's no active group (or active is invalid), create a new menu to find it */
+ if (pose->active_group <= 0) {
+ /* create a new menu, and start populating it with group names */
+ pup = uiPupMenuBegin(C, op->type->name, ICON_NONE);
+ layout = uiPupMenuLayout(pup);
+
+ /* special entry - allow to create new group, then use that
+ * (not to be used for removing though)
+ */
+ if (strstr(op->idname, "assign")) {
+ uiItemIntO(layout, "New Group", ICON_NONE, op->idname, "type", 0);
+ uiItemS(layout);
+ }
+
+ /* add entries for each group */
+ for (grp = pose->agroups.first, i = 1; grp; grp = grp->next, i++)
+ uiItemIntO(layout, grp->name, ICON_NONE, op->idname, "type", i);
+
+ /* finish building the menu, and process it (should result in calling self again) */
+ uiPupMenuEnd(C, pup);
+
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ /* just use the active group index, and call the exec callback for the calling operator */
+ RNA_int_set(op->ptr, "type", pose->active_group);
+ return op->type->exec(C, op);
+ }
+}
+
+/* Assign selected pchans to the bone group that the user selects */
+static int pose_group_assign_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_pose_object_from_context(C);
+ bPose *pose;
+ short done = FALSE;
+
+ /* only continue if there's an object, and a pose there too */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ pose = ob->pose;
+
+ /* set the active group number to the one from operator props
+ * - if 0 after this, make a new group...
+ */
+ pose->active_group = RNA_int_get(op->ptr, "type");
+ if (pose->active_group == 0)
+ BKE_pose_add_group(ob);
+
+ /* add selected bones to group then */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ pchan->agrp_index = pose->active_group;
+ done = TRUE;
+ }
+ CTX_DATA_END;
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ /* report done status */
+ if (done)
+ return OPERATOR_FINISHED;
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void POSE_OT_group_assign(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Selected to Bone Group";
+ ot->idname = "POSE_OT_group_assign";
+ ot->description = "Add selected bones to the chosen bone group";
+
+ /* api callbacks */
+ ot->invoke = pose_groups_menu_invoke;
+ ot->exec = pose_group_assign_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_int(ot->srna, "type", 0, 0, INT_MAX, "Bone Group Index", "", 0, 10);
+}
+
+
+static int pose_group_unassign_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_pose_object_from_context(C);
+ short done = FALSE;
+
+ /* only continue if there's an object, and a pose there too */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ /* find selected bones to remove from all bone groups */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ if (pchan->agrp_index) {
+ pchan->agrp_index = 0;
+ done = TRUE;
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ /* report done status */
+ if (done)
+ return OPERATOR_FINISHED;
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void POSE_OT_group_unassign(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Selected from Bone Groups";
+ ot->idname = "POSE_OT_group_unassign";
+ ot->description = "Remove selected bones from all bone groups";
+
+ /* api callbacks */
+ ot->exec = pose_group_unassign_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int group_move_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_pose_object_from_context(C);
+ bPose *pose = (ob) ? ob->pose : NULL;
+ bPoseChannel *pchan;
+ bActionGroup *grp;
+ int dir = RNA_enum_get(op->ptr, "direction");
+ int grpIndexA, grpIndexB;
+
+ if (ELEM(NULL, ob, pose))
+ return OPERATOR_CANCELLED;
+ if (pose->active_group <= 0)
+ return OPERATOR_CANCELLED;
+
+ /* get group to move */
+ grp = BLI_findlink(&pose->agroups, pose->active_group - 1);
+ if (grp == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* move bone group */
+ grpIndexA = pose->active_group;
+ if (dir == 1) { /* up */
+ void *prev = grp->prev;
+
+ if (prev == NULL)
+ return OPERATOR_FINISHED;
+
+ BLI_remlink(&pose->agroups, grp);
+ BLI_insertlinkbefore(&pose->agroups, prev, grp);
+
+ grpIndexB = grpIndexA - 1;
+ pose->active_group--;
+ }
+ else { /* down */
+ void *next = grp->next;
+
+ if (next == NULL)
+ return OPERATOR_FINISHED;
+
+ BLI_remlink(&pose->agroups, grp);
+ BLI_insertlinkafter(&pose->agroups, next, grp);
+
+ grpIndexB = grpIndexA + 1;
+ pose->active_group++;
+ }
+
+ /* fix changed bone group indices in bones (swap grpIndexA with grpIndexB) */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->agrp_index == grpIndexB)
+ pchan->agrp_index = grpIndexA;
+ else if (pchan->agrp_index == grpIndexA)
+ pchan->agrp_index = grpIndexB;
+ }
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_group_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem group_slot_move[] = {
+ {1, "UP", 0, "Up", ""},
+ {-1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Move Bone Group";
+ ot->idname = "POSE_OT_group_move";
+ ot->description = "Change position of active Bone Group in list of Bone Groups";
+
+ /* api callbacks */
+ ot->exec = group_move_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "direction", group_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
+}
+
+/* bone group sort element */
+typedef struct tSortActionGroup {
+ bActionGroup *agrp;
+ int index;
+} tSortActionGroup;
+
+/* compare bone groups by name */
+static int compare_agroup(const void *sgrp_a_ptr, const void *sgrp_b_ptr)
+{
+ tSortActionGroup *sgrp_a = (tSortActionGroup *)sgrp_a_ptr;
+ tSortActionGroup *sgrp_b = (tSortActionGroup *)sgrp_b_ptr;
+
+ return strcmp(sgrp_a->agrp->name, sgrp_b->agrp->name);
+}
+
+static int group_sort_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_pose_object_from_context(C);
+ bPose *pose = (ob) ? ob->pose : NULL;
+ bPoseChannel *pchan;
+ tSortActionGroup *agrp_array;
+ bActionGroup *agrp;
+ int agrp_count;
+ int i;
+
+ if (ELEM(NULL, ob, pose))
+ return OPERATOR_CANCELLED;
+ if (pose->active_group <= 0)
+ return OPERATOR_CANCELLED;
+
+ /* create temporary array with bone groups and indices */
+ agrp_count = BLI_countlist(&pose->agroups);
+ agrp_array = MEM_mallocN(sizeof(tSortActionGroup) * agrp_count, "sort bone groups");
+ for (agrp = pose->agroups.first, i = 0; agrp; agrp = agrp->next, i++) {
+ BLI_assert(i < agrp_count);
+ agrp_array[i].agrp = agrp;
+ agrp_array[i].index = i + 1;
+ }
+
+ /* sort bone groups by name */
+ qsort(agrp_array, agrp_count, sizeof(tSortActionGroup), compare_agroup);
+
+ /* create sorted bone group list from sorted array */
+ pose->agroups.first = pose->agroups.last = NULL;
+ for (i = 0; i < agrp_count; i++) {
+ BLI_addtail(&pose->agroups, agrp_array[i].agrp);
+ }
+
+ /* fix changed bone group indizes in bones */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ for (i = 0; i < agrp_count; i++) {
+ if (pchan->agrp_index == agrp_array[i].index) {
+ pchan->agrp_index = i + 1;
+ break;
+ }
+ }
+ }
+
+ /* free temp resources */
+ MEM_freeN(agrp_array);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_group_sort(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Sort Bone Groups";
+ ot->idname = "POSE_OT_group_sort";
+ ot->description = "Sort Bone Groups by their names in ascending order";
+
+ /* api callbacks */
+ ot->exec = group_sort_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static void pose_group_select(bContext *C, Object *ob, int select)
+{
+ bPose *pose = ob->pose;
+
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
+ if (select) {
+ if (pchan->agrp_index == pose->active_group)
+ pchan->bone->flag |= BONE_SELECTED;
+ }
+ else {
+ if (pchan->agrp_index == pose->active_group)
+ pchan->bone->flag &= ~BONE_SELECTED;
+ }
+ }
+ }
+ CTX_DATA_END;
+}
+
+static int pose_group_select_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_pose_object_from_context(C);
+
+ /* only continue if there's an object, and a pose there too */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ pose_group_select(C, ob, 1);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_group_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Bones of Bone Group";
+ ot->idname = "POSE_OT_group_select";
+ ot->description = "Select bones in active Bone Group";
+
+ /* api callbacks */
+ ot->exec = pose_group_select_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int pose_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_pose_object_from_context(C);
+
+ /* only continue if there's an object, and a pose there too */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ pose_group_select(C, ob, 0);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_group_deselect(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Deselect Bone Group";
+ ot->idname = "POSE_OT_group_deselect";
+ ot->description = "Deselect bones of active Bone Group";
+
+ /* api callbacks */
+ ot->exec = pose_group_deselect_exec;
+ ot->poll = ED_operator_posemode_context;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************************** */
diff --git a/source/blender/editors/armature/poselib.c b/source/blender/editors/armature/pose_lib.c
index 48c0a4a38c3..457874c7ae6 100644
--- a/source/blender/editors/armature/poselib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -23,25 +23,17 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/editors/armature/poselib.c
+/** \file blender/editors/armature/pose_lib.c
* \ingroup edarmature
*/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
#include <string.h>
#include <math.h>
-#include <float.h>
#include "MEM_guardedalloc.h"
-#include "BLI_math.h"
#include "BLI_blenlib.h"
-#include "BLI_dynstr.h"
#include "BLI_dlrbTree.h"
-#include "BLI_utildefines.h"
#include "BLF_translation.h"
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
new file mode 100644
index 00000000000..186c7a1fe89
--- /dev/null
+++ b/source/blender/editors/armature/pose_select.c
@@ -0,0 +1,853 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/armature/pose_select.c
+ * \ingroup edarmature
+ */
+
+#include <string.h>
+
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_object.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_keyframing.h"
+#include "ED_mesh.h"
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "armature_intern.h"
+
+/* ***************** Pose Select Utilities ********************* */
+
+/* called from editview.c, for mode-less pose selection */
+/* assumes scene obact and basact is still on old situation */
+int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits,
+ short extend, short deselect, short toggle)
+{
+ Object *ob = base->object;
+ Bone *nearBone;
+
+ if (!ob || !ob->pose) return 0;
+
+ nearBone = get_bone_from_selectbuffer(scene, base, buffer, hits, 1);
+
+ /* if the bone cannot be affected, don't do anything */
+ if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) {
+ Object *ob_act = OBACT;
+ bArmature *arm = ob->data;
+
+ /* since we do unified select, we don't shift+select a bone if the
+ * armature object was not active yet.
+ * note, special exception for armature mode so we can do multi-select
+ * we could check for multi-select explicitly but think its fine to
+ * always give predictable behavior in weight paint mode - campbell */
+ if ((!extend && !deselect && !toggle) ||
+ ((ob_act && (ob_act != ob) && (ob_act->mode & OB_MODE_WEIGHT_PAINT) == 0)))
+ {
+ ED_pose_deselectall(ob, 0);
+ nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_bone = nearBone;
+ }
+ else {
+ if (extend) {
+ nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_bone = nearBone;
+ }
+ else if (deselect) {
+ nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else if (toggle) {
+ if (nearBone->flag & BONE_SELECTED) {
+ /* if not active, we make it active */
+ if (nearBone != arm->act_bone) {
+ arm->act_bone = nearBone;
+ }
+ else {
+ nearBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ }
+ else {
+ nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_bone = nearBone;
+ }
+ }
+ }
+
+ if (ob_act) {
+ /* in weightpaint we select the associated vertex group too */
+ if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
+ if (nearBone == arm->act_bone) {
+ ED_vgroup_select_by_name(ob_act, nearBone->name);
+ DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
+ }
+ }
+ /* if there are some dependencies for visualizing armature state
+ * (e.g. Mask Modifier in 'Armature' mode), force update
+ */
+ else if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
+ }
+ }
+ }
+
+ return nearBone != NULL;
+}
+
+/* test==0: deselect all
+ * test==1: swap select (apply to all the opposite of current situation)
+ * test==2: only clear active tag
+ * test==3: swap select (no test / inverse selection status of all independently)
+ */
+void ED_pose_deselectall(Object *ob, int test)
+{
+ bArmature *arm = ob->data;
+ bPoseChannel *pchan;
+ int selectmode = 0;
+
+ /* we call this from outliner too */
+ if (ob->pose == NULL) {
+ return;
+ }
+
+ /* Determine if we're selecting or deselecting */
+ if (test == 1) {
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (PBONE_VISIBLE(arm, pchan->bone)) {
+ if (pchan->bone->flag & BONE_SELECTED)
+ break;
+ }
+ }
+
+ if (pchan == NULL)
+ selectmode = 1;
+ }
+ else if (test == 2)
+ selectmode = 2;
+
+ /* Set the flags accordingly */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* ignore the pchan if it isn't visible or if its selection cannot be changed */
+ if ((pchan->bone->layer & arm->layer) && !(pchan->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
+ if (test == 3) {
+ pchan->bone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ if (selectmode == 0) pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ else if (selectmode == 1) pchan->bone->flag |= BONE_SELECTED;
+ }
+ }
+ }
+}
+
+/* ***************** Selections ********************** */
+
+static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
+{
+ Bone *curBone;
+
+ /* stop when unconnected child is encontered, or when unselectable bone is encountered */
+ if (!(bone->flag & BONE_CONNECTED) || (bone->flag & BONE_UNSELECTABLE))
+ return;
+
+ /* XXX old cruft! use notifiers instead */
+ //select_actionchannel_by_name (ob->action, bone->name, !(shift));
+
+ if (extend)
+ bone->flag &= ~BONE_SELECTED;
+ else
+ bone->flag |= BONE_SELECTED;
+
+ for (curBone = bone->childbase.first; curBone; curBone = curBone->next)
+ selectconnected_posebonechildren(ob, curBone, extend);
+}
+
+/* within active object context */
+/* previously known as "selectconnected_posearmature" */
+static int pose_select_connected_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = (bArmature *)ob->data;
+ Bone *bone, *curBone, *next = NULL;
+ int extend = RNA_boolean_get(op->ptr, "extend");
+
+ view3d_operator_needs_opengl(C);
+
+ if (extend)
+ bone = get_nearest_bone(C, 0, event->mval[0], event->mval[1]);
+ else
+ bone = get_nearest_bone(C, 1, event->mval[0], event->mval[1]);
+
+ if (!bone)
+ return OPERATOR_CANCELLED;
+
+ /* Select parents */
+ for (curBone = bone; curBone; curBone = next) {
+ /* ignore bone if cannot be selected */
+ if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
+ if (extend)
+ curBone->flag &= ~BONE_SELECTED;
+ else
+ curBone->flag |= BONE_SELECTED;
+
+ if (curBone->flag & BONE_CONNECTED)
+ next = curBone->parent;
+ else
+ next = NULL;
+ }
+ else
+ next = NULL;
+ }
+
+ /* Select children */
+ for (curBone = bone->childbase.first; curBone; curBone = next)
+ selectconnected_posebonechildren(ob, curBone, extend);
+
+ /* updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ /* mask modifier ('armature' mode), etc. */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static int pose_select_linked_poll(bContext *C)
+{
+ return (ED_operator_view3d_active(C) && ED_operator_posemode(C));
+}
+
+void POSE_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Connected";
+ ot->idname = "POSE_OT_select_linked";
+ ot->description = "Select bones related to selected ones by parent/child relationships";
+
+ /* api callbacks */
+ ot->exec = NULL;
+ ot->invoke = pose_select_connected_invoke;
+ ot->poll = pose_select_linked_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
+}
+
+/* -------------------------------------- */
+
+static int pose_de_select_all_exec(bContext *C, wmOperator *op)
+{
+ int action = RNA_enum_get(op->ptr, "action");
+
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = ED_object_context(C);
+ bArmature *arm = ob->data;
+ int multipaint = scene->toolsettings->multipaint;
+
+ if (action == SEL_TOGGLE) {
+ action = CTX_DATA_COUNT(C, selected_pose_bones) ? SEL_DESELECT : SEL_SELECT;
+ }
+
+ /* Set the flags */
+ CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ /* select pchan only if selectable, but deselect works always */
+ switch (action) {
+ case SEL_SELECT:
+ if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)
+ pchan->bone->flag |= BONE_SELECTED;
+ break;
+ case SEL_DESELECT:
+ pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ break;
+ case SEL_INVERT:
+ if (pchan->bone->flag & BONE_SELECTED) {
+ pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
+ pchan->bone->flag |= BONE_SELECTED;
+ }
+ break;
+ }
+ }
+ CTX_DATA_END;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
+
+ /* weightpaint or mask modifiers need depsgraph updates */
+ if (multipaint || (arm->flag & ARM_HAS_VIZ_DEPS)) {
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_select_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "(De)select All";
+ ot->idname = "POSE_OT_select_all";
+ ot->description = "Toggle selection status of all bones";
+
+ /* api callbacks */
+ ot->exec = pose_de_select_all_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ WM_operator_properties_select_all(ot);
+}
+
+/* -------------------------------------- */
+
+static int pose_select_parent_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = (bArmature *)ob->data;
+ bPoseChannel *pchan, *parent;
+
+ /* Determine if there is an active bone */
+ pchan = CTX_data_active_pose_bone(C);
+ if (pchan) {
+ parent = pchan->parent;
+ if ((parent) && !(parent->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
+ parent->bone->flag |= BONE_SELECTED;
+ arm->act_bone = parent->bone;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ /* mask modifier ('armature' mode), etc. */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_select_parent(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Parent Bone";
+ ot->idname = "POSE_OT_select_parent";
+ ot->description = "Select bones that are parents of the currently selected bones";
+
+ /* api callbacks */
+ ot->exec = pose_select_parent_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* -------------------------------------- */
+
+static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = (bArmature *)ob->data;
+ bConstraint *con;
+ int found = 0;
+
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ if (pchan->bone->flag & BONE_SELECTED) {
+ for (con = pchan->constraints.first; con; con = con->next) {
+ bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct = targets.first; ct; ct = ct->next) {
+ if ((ct->tar == ob) && (ct->subtarget[0])) {
+ bPoseChannel *pchanc = BKE_pose_channel_find_name(ob->pose, ct->subtarget);
+ if ((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) {
+ pchanc->bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
+ found = 1;
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 1);
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ if (!found)
+ return OPERATOR_CANCELLED;
+
+ /* updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ /* mask modifier ('armature' mode), etc. */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_select_constraint_target(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Constraint Target";
+ ot->idname = "POSE_OT_select_constraint_target";
+ ot->description = "Select bones used as targets for the currently selected bones";
+
+ /* api callbacks */
+ ot->exec = pose_select_constraint_target_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* -------------------------------------- */
+
+static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = ob->data;
+ Bone *curbone, *pabone, *chbone;
+ int direction = RNA_enum_get(op->ptr, "direction");
+ int add_to_sel = RNA_boolean_get(op->ptr, "extend");
+ int found = 0;
+
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ curbone = pchan->bone;
+
+ if ((curbone->flag & BONE_UNSELECTABLE) == 0) {
+ if (curbone == arm->act_bone) {
+ if (direction == BONE_SELECT_PARENT) {
+ if (pchan->parent == NULL) continue;
+ else pabone = pchan->parent->bone;
+
+ if (PBONE_SELECTABLE(arm, pabone)) {
+ if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
+ pabone->flag |= BONE_SELECTED;
+ arm->act_bone = pabone;
+
+ found = 1;
+ break;
+ }
+ }
+ else { /* direction == BONE_SELECT_CHILD */
+ /* the child member is only assigned to connected bones, see [#30340] */
+#if 0
+ if (pchan->child == NULL) continue;
+ else chbone = pchan->child->bone;
+#else
+ /* instead. find _any_ visible child bone, using the first one is a little arbitrary - campbell */
+ chbone = pchan->child ? pchan->child->bone : NULL;
+ if (chbone == NULL) {
+ bPoseChannel *pchan_child;
+
+ for (pchan_child = ob->pose->chanbase.first; pchan_child; pchan_child = pchan_child->next) {
+ /* possible we have multiple children, some invisible */
+ if (PBONE_SELECTABLE(arm, pchan_child->bone)) {
+ if (pchan_child->parent == pchan) {
+ chbone = pchan_child->bone;
+ break;
+ }
+ }
+ }
+ }
+
+ if (chbone == NULL) continue;
+#endif
+
+ if (PBONE_SELECTABLE(arm, chbone)) {
+ if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
+ chbone->flag |= BONE_SELECTED;
+ arm->act_bone = chbone;
+
+ found = 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ if (found == 0)
+ return OPERATOR_CANCELLED;
+
+ /* updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ /* mask modifier ('armature' mode), etc. */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_select_hierarchy(wmOperatorType *ot)
+{
+ static EnumPropertyItem direction_items[] = {
+ {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
+ {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Select Hierarchy";
+ ot->idname = "POSE_OT_select_hierarchy";
+ ot->description = "Select immediate parent/children of selected bones";
+
+ /* api callbacks */
+ ot->exec = pose_select_hierarchy_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ ot->prop = RNA_def_enum(ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", "");
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
+}
+
+/* -------------------------------------- */
+
+static short pose_select_same_group(bContext *C, Object *ob, short extend)
+{
+ bArmature *arm = (ob) ? ob->data : NULL;
+ bPose *pose = (ob) ? ob->pose : NULL;
+ char *group_flags;
+ int numGroups = 0;
+ short changed = 0, tagged = 0;
+
+ /* sanity checks */
+ if (ELEM3(NULL, ob, pose, arm))
+ return 0;
+
+ /* count the number of groups */
+ numGroups = BLI_countlist(&pose->agroups);
+ if (numGroups == 0)
+ return 0;
+
+ /* alloc a small array to keep track of the groups to use
+ * - each cell stores on/off state for whether group should be used
+ * - size is (numGroups + 1), since (index = 0) is used for no-group
+ */
+ group_flags = MEM_callocN(numGroups + 1, "pose_select_same_group");
+
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ /* keep track of group as group to use later? */
+ if (pchan->bone->flag & BONE_SELECTED) {
+ group_flags[pchan->agrp_index] = 1;
+ tagged = 1;
+ }
+
+ /* deselect all bones before selecting new ones? */
+ if ((extend == 0) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0)
+ pchan->bone->flag &= ~BONE_SELECTED;
+ }
+ CTX_DATA_END;
+
+ /* small optimization: only loop through bones a second time if there are any groups tagged */
+ if (tagged) {
+ /* only if group matches (and is not selected or current bone) */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
+ /* check if the group used by this bone is counted */
+ if (group_flags[pchan->agrp_index]) {
+ pchan->bone->flag |= BONE_SELECTED;
+ changed = 1;
+ }
+ }
+ }
+ CTX_DATA_END;
+ }
+
+ /* free temp info */
+ MEM_freeN(group_flags);
+
+ return changed;
+}
+
+static short pose_select_same_layer(bContext *C, Object *ob, short extend)
+{
+ bPose *pose = (ob) ? ob->pose : NULL;
+ bArmature *arm = (ob) ? ob->data : NULL;
+ short changed = 0;
+ int layers = 0;
+
+ if (ELEM3(NULL, ob, pose, arm))
+ return 0;
+
+ /* figure out what bones are selected */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ /* keep track of layers to use later? */
+ if (pchan->bone->flag & BONE_SELECTED)
+ layers |= pchan->bone->layer;
+
+ /* deselect all bones before selecting new ones? */
+ if ((extend == 0) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0)
+ pchan->bone->flag &= ~BONE_SELECTED;
+ }
+ CTX_DATA_END;
+ if (layers == 0)
+ return 0;
+
+ /* select bones that are on same layers as layers flag */
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ /* if bone is on a suitable layer, and the bone can have its selection changed, select it */
+ if ((layers & pchan->bone->layer) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
+ pchan->bone->flag |= BONE_SELECTED;
+ changed = 1;
+ }
+ }
+ CTX_DATA_END;
+
+ return changed;
+}
+
+static int pose_select_same_keyingset(bContext *C, Object *ob, short extend)
+{
+ KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C));
+ KS_Path *ksp;
+
+ bArmature *arm = (ob) ? ob->data : NULL;
+ bPose *pose = (ob) ? ob->pose : NULL;
+ short changed = 0;
+
+ /* sanity checks: validate Keying Set and object */
+ if ((ks == NULL) || (ANIM_validate_keyingset(C, NULL, ks) != 0))
+ return 0;
+
+ if (ELEM3(NULL, ob, pose, arm))
+ return 0;
+
+ /* if not extending selection, deselect all selected first */
+ if (extend == 0) {
+ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
+ {
+ if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)
+ pchan->bone->flag &= ~BONE_SELECTED;
+ }
+ CTX_DATA_END;
+ }
+
+ /* iterate over elements in the Keying Set, setting selection depending on whether
+ * that bone is visible or not...
+ */
+ for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
+ /* only items related to this object will be relevant */
+ if ((ksp->id == &ob->id) && (ksp->rna_path != NULL)) {
+ if (strstr(ksp->rna_path, "bones")) {
+ char *boneName = BLI_str_quoted_substrN(ksp->rna_path, "bones[");
+
+ if (boneName) {
+ bPoseChannel *pchan = BKE_pose_channel_find_name(pose, boneName);
+
+ if (pchan) {
+ /* select if bone is visible and can be affected */
+ if (PBONE_SELECTABLE(arm, pchan->bone)) {
+ pchan->bone->flag |= BONE_SELECTED;
+ changed = 1;
+ }
+ }
+
+ /* free temp memory */
+ MEM_freeN(boneName);
+ }
+ }
+ }
+ }
+
+ return changed;
+}
+
+static int pose_select_grouped_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ bArmature *arm = (bArmature *)ob->data;
+ short extend = RNA_boolean_get(op->ptr, "extend");
+ short changed = 0;
+
+ /* sanity check */
+ if (ob->pose == NULL)
+ return OPERATOR_CANCELLED;
+
+ /* selection types
+ * NOTE: for the order of these, see the enum in POSE_OT_select_grouped()
+ */
+ switch (RNA_enum_get(op->ptr, "type")) {
+ case 1: /* group */
+ changed = pose_select_same_group(C, ob, extend);
+ break;
+ case 2: /* Keying Set */
+ changed = pose_select_same_keyingset(C, ob, extend);
+ break;
+ default: /* layer */
+ changed = pose_select_same_layer(C, ob, extend);
+ break;
+ }
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ /* mask modifier ('armature' mode), etc. */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+
+ /* report done status */
+ if (changed)
+ return OPERATOR_FINISHED;
+ else
+ return OPERATOR_CANCELLED;
+}
+
+void POSE_OT_select_grouped(wmOperatorType *ot)
+{
+ static EnumPropertyItem prop_select_grouped_types[] = {
+ {0, "LAYER", 0, "Layer", "Shared layers"},
+ {1, "GROUP", 0, "Group", "Shared group"},
+ {2, "KEYINGSET", 0, "Keying Set", "All bones affected by active Keying Set"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Select Grouped";
+ ot->description = "Select all visible bones grouped by similar properties";
+ ot->idname = "POSE_OT_select_grouped";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = pose_select_grouped_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
+}
+
+/* -------------------------------------- */
+
+/* context active object, or weightpainted object with armature in posemode */
+static int pose_bone_flip_active_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob_act = CTX_data_active_object(C);
+ Object *ob = BKE_object_pose_armature_get(ob_act);
+
+ if (ob && (ob->mode & OB_MODE_POSE)) {
+ bArmature *arm = ob->data;
+
+ if (arm->act_bone) {
+ bPoseChannel *pchanf;
+ char name[MAXBONENAME];
+ flip_side_name(name, arm->act_bone->name, TRUE);
+
+ pchanf = BKE_pose_channel_find_name(ob->pose, name);
+ if (pchanf && pchanf->bone != arm->act_bone) {
+ arm->act_bone->flag &= ~BONE_SELECTED;
+ pchanf->bone->flag |= BONE_SELECTED;
+
+ arm->act_bone = pchanf->bone;
+
+ /* in weightpaint we select the associated vertex group too */
+ if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
+ ED_vgroup_select_by_name(ob_act, name);
+ DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
+
+ return OPERATOR_FINISHED;
+ }
+ }
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void POSE_OT_select_flip_active(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Flip Selected Active Bone";
+ ot->idname = "POSE_OT_select_flip_active";
+ ot->description = "Activate the bone with a flipped name";
+
+ /* api callbacks */
+ ot->exec = pose_bone_flip_active_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
diff --git a/source/blender/editors/armature/poseSlide.c b/source/blender/editors/armature/pose_slide.c
index 3fd65de6c04..fee37a9c0fb 100644
--- a/source/blender/editors/armature/poseSlide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -23,25 +23,15 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/editors/armature/poseSlide.c
+/** \file blender/editors/armature/pose_slide.c
* \ingroup edarmature
*/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <string.h>
-#include <math.h>
-#include <float.h>
-
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
-#include "BLI_dynstr.h"
#include "BLI_dlrbTree.h"
-#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
new file mode 100644
index 00000000000..2525641e58c
--- /dev/null
+++ b/source/blender/editors/armature/pose_transform.c
@@ -0,0 +1,879 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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.
+ *
+ * Contributor(s): Blender Foundation, 2002-2009 full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/armature/pose_transform.c
+ * \ingroup edarmature
+ */
+
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BKE_animsys.h"
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_idprop.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_keyframing.h"
+#include "ED_screen.h"
+#include "ED_util.h"
+
+#include "armature_intern.h"
+
+
+/* ********************************************** */
+/* Pose Apply */
+
+/* helper for apply_armature_pose2bones - fixes parenting of objects that are bone-parented to armature */
+static void applyarmature_fix_boneparents(Scene *scene, Object *armob)
+{
+ Object workob, *ob;
+
+ /* go through all objects in database */
+ for (ob = G.main->object.first; ob; ob = ob->id.next) {
+ /* if parent is bone in this armature, apply corrections */
+ if ((ob->parent == armob) && (ob->partype == PARBONE)) {
+ /* apply current transform from parent (not yet destroyed),
+ * then calculate new parent inverse matrix
+ */
+ BKE_object_apply_mat4(ob, ob->obmat, FALSE, FALSE);
+
+ BKE_object_workob_calc_parent(scene, ob, &workob);
+ invert_m4_m4(ob->parentinv, workob.obmat);
+ }
+ }
+}
+
+/* set the current pose as the restpose */
+static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object
+ bArmature *arm = BKE_armature_from_object(ob);
+ bPose *pose;
+ bPoseChannel *pchan;
+ EditBone *curbone;
+
+ /* don't check if editmode (should be done by caller) */
+ if (ob->type != OB_ARMATURE)
+ return OPERATOR_CANCELLED;
+ if (BKE_object_obdata_is_libdata(ob)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot apply pose to lib-linked armature"); /* error_libdata(); */
+ return OPERATOR_CANCELLED;
+ }
+
+ /* helpful warnings... */
+ /* TODO: add warnings to be careful about actions, applying deforms first, etc. */
+ if (ob->adt && ob->adt->action)
+ BKE_report(op->reports, RPT_WARNING,
+ "Actions on this armature will be destroyed by this new rest pose as the "
+ "transforms stored are relative to the old rest pose");
+
+ /* Get editbones of active armature to alter */
+ ED_armature_to_edit(ob);
+
+ /* get pose of active object and move it out of posemode */
+ pose = ob->pose;
+
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ curbone = editbone_name_exists(arm->edbo, pchan->name);
+
+ /* simply copy the head/tail values from pchan over to curbone */
+ copy_v3_v3(curbone->head, pchan->pose_head);
+ copy_v3_v3(curbone->tail, pchan->pose_tail);
+
+ /* fix roll:
+ * 1. find auto-calculated roll value for this bone now
+ * 2. remove this from the 'visual' y-rotation
+ */
+ {
+ float premat[3][3], imat[3][3], pmat[3][3], tmat[3][3];
+ float delta[3], eul[3];
+
+ /* obtain new auto y-rotation */
+ sub_v3_v3v3(delta, curbone->tail, curbone->head);
+ vec_roll_to_mat3(delta, 0.0f, premat);
+ invert_m3_m3(imat, premat);
+
+ /* get pchan 'visual' matrix */
+ copy_m3_m4(pmat, pchan->pose_mat);
+
+ /* remove auto from visual and get euler rotation */
+ mul_m3_m3m3(tmat, imat, pmat);
+ mat3_to_eul(eul, tmat);
+
+ /* just use this euler-y as new roll value */
+ curbone->roll = eul[1];
+ }
+
+ /* clear transform values for pchan */
+ zero_v3(pchan->loc);
+ zero_v3(pchan->eul);
+ unit_qt(pchan->quat);
+ unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
+ pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f;
+
+ /* set anim lock */
+ curbone->flag |= BONE_UNKEYED;
+ }
+
+ /* convert editbones back to bones, and then free the edit-data */
+ ED_armature_from_edit(ob);
+ ED_armature_edit_free(ob);
+
+ /* flush positions of posebones */
+ BKE_pose_where_is(scene, ob);
+
+ /* fix parenting of objects which are bone-parented */
+ applyarmature_fix_boneparents(scene, ob);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_armature_apply(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Apply Pose as Rest Pose";
+ ot->idname = "POSE_OT_armature_apply";
+ ot->description = "Apply the current pose as the new rest pose";
+
+ /* callbacks */
+ ot->exec = apply_armature_pose2bones_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+/* set the current pose as the restpose */
+static int pose_visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object
+
+ /* don't check if editmode (should be done by caller) */
+ if (ob->type != OB_ARMATURE)
+ return OPERATOR_CANCELLED;
+
+ /* loop over all selected pchans
+ *
+ * TODO, loop over children before parents if multiple bones
+ * at once are to be predictable*/
+ CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ float delta_mat[4][4];
+
+ /* chan_mat already contains the delta transform from rest pose to pose-mode pose
+ * as that is baked into there so that B-Bones will work. Once we've set this as the
+ * new raw-transform components, don't recalc the poses yet, otherwise IK result will
+ * change, thus changing the result we may be trying to record.
+ */
+ copy_m4_m4(delta_mat, pchan->chan_mat);
+ BKE_pchan_apply_mat4(pchan, delta_mat, TRUE);
+ }
+ CTX_DATA_END;
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_visual_transform_apply(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Apply Visual Transform to Pose";
+ ot->idname = "POSE_OT_visual_transform_apply";
+ ot->description = "Apply final constrained position of pose bones to their transform";
+
+ /* callbacks */
+ ot->exec = pose_visual_transform_apply_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************************** */
+/* Copy/Paste */
+
+/* Global copy/paste buffer for pose - cleared on start/end session + before every copy operation */
+static bPose *g_posebuf = NULL;
+
+void ED_clipboard_posebuf_free(void)
+{
+ if (g_posebuf) {
+ bPoseChannel *pchan;
+
+ for (pchan = g_posebuf->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->prop) {
+ IDP_FreeProperty(pchan->prop);
+ MEM_freeN(pchan->prop);
+ }
+ }
+
+ /* was copied without constraints */
+ BLI_freelistN(&g_posebuf->chanbase);
+ MEM_freeN(g_posebuf);
+ }
+
+ g_posebuf = NULL;
+}
+
+/* This function is used to indicate that a bone is selected
+ * and needs to be included in copy buffer (used to be for inserting keys)
+ */
+static void set_pose_keys(Object *ob)
+{
+ bArmature *arm = ob->data;
+ bPoseChannel *chan;
+
+ if (ob->pose) {
+ for (chan = ob->pose->chanbase.first; chan; chan = chan->next) {
+ Bone *bone = chan->bone;
+ if ((bone) && (bone->flag & BONE_SELECTED) && (arm->layer & bone->layer))
+ chan->flag |= POSE_KEY;
+ else
+ chan->flag &= ~POSE_KEY;
+ }
+ }
+}
+
+/* perform paste pose, for a single bone
+ * < ob: object where bone to paste to lives
+ * < chan: bone that pose to paste comes from
+ * < selOnly: only paste on selected bones
+ * < flip: flip on x-axis
+ *
+ * > returns: whether the bone that we pasted to if we succeeded
+ */
+static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, short selOnly, short flip)
+{
+ bPoseChannel *pchan;
+ char name[MAXBONENAME];
+ short paste_ok;
+
+ /* get the name - if flipping, we must flip this first */
+ if (flip)
+ flip_side_name(name, chan->name, 0); /* 0 = don't strip off number extensions */
+ else
+ BLI_strncpy(name, chan->name, sizeof(name));
+
+ /* only copy when:
+ * 1) channel exists - poses are not meant to add random channels to anymore
+ * 2) if selection-masking is on, channel is selected - only selected bones get pasted on, allowing making both sides symmetrical
+ */
+ pchan = BKE_pose_channel_find_name(ob->pose, name);
+
+ if (selOnly)
+ paste_ok = ((pchan) && (pchan->bone->flag & BONE_SELECTED));
+ else
+ paste_ok = ((pchan != NULL));
+
+ /* continue? */
+ if (paste_ok) {
+ /* only loc rot size
+ * - only copies transform info for the pose
+ */
+ copy_v3_v3(pchan->loc, chan->loc);
+ copy_v3_v3(pchan->size, chan->size);
+ pchan->flag = chan->flag;
+
+ /* check if rotation modes are compatible (i.e. do they need any conversions) */
+ if (pchan->rotmode == chan->rotmode) {
+ /* copy the type of rotation in use */
+ if (pchan->rotmode > 0) {
+ copy_v3_v3(pchan->eul, chan->eul);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ copy_v3_v3(pchan->rotAxis, chan->rotAxis);
+ pchan->rotAngle = chan->rotAngle;
+ }
+ else {
+ copy_qt_qt(pchan->quat, chan->quat);
+ }
+ }
+ else if (pchan->rotmode > 0) {
+ /* quat/axis-angle to euler */
+ if (chan->rotmode == ROT_MODE_AXISANGLE)
+ axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle);
+ else
+ quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ /* quat/euler to axis angle */
+ if (chan->rotmode > 0)
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
+ else
+ quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
+ }
+ else {
+ /* euler/axis-angle to quat */
+ if (chan->rotmode > 0)
+ eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
+ else
+ axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
+ }
+
+ /* paste flipped pose? */
+ if (flip) {
+ pchan->loc[0] *= -1;
+
+ /* has to be done as eulers... */
+ if (pchan->rotmode > 0) {
+ pchan->eul[1] *= -1;
+ pchan->eul[2] *= -1;
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ float eul[3];
+
+ axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
+ eul[1] *= -1;
+ eul[2] *= -1;
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
+ }
+ else {
+ float eul[3];
+
+ normalize_qt(pchan->quat);
+ quat_to_eul(eul, pchan->quat);
+ eul[1] *= -1;
+ eul[2] *= -1;
+ eul_to_quat(pchan->quat, eul);
+ }
+ }
+
+ /* ID properties */
+ if (chan->prop) {
+ if (pchan->prop) {
+ /* if we have existing properties on a bone, just copy over the values of
+ * matching properties (i.e. ones which will have some impact) on to the
+ * target instead of just blinding replacing all [
+ */
+ IDP_SyncGroupValues(pchan->prop, chan->prop);
+ }
+ else {
+ /* no existing properties, so assume that we want copies too? */
+ pchan->prop = IDP_CopyProperty(chan->prop);
+ }
+ }
+ }
+
+ /* return whether paste went ahead */
+ return pchan;
+}
+
+/* ---- */
+
+static int pose_copy_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+
+ /* sanity checking */
+ if (ELEM(NULL, ob, ob->pose)) {
+ BKE_report(op->reports, RPT_ERROR, "No pose to copy");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* free existing pose buffer */
+ ED_clipboard_posebuf_free();
+
+ /* sets chan->flag to POSE_KEY if bone selected, then copy those bones to the buffer */
+ set_pose_keys(ob);
+ BKE_pose_copy_data(&g_posebuf, ob->pose, 0);
+
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_copy(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Copy Pose";
+ ot->idname = "POSE_OT_copy";
+ ot->description = "Copies the current pose of the selected bones to copy/paste buffer";
+
+ /* api callbacks */
+ ot->exec = pose_copy_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flag */
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/* ---- */
+
+static int pose_paste_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ Scene *scene = CTX_data_scene(C);
+ bPoseChannel *chan;
+ int flip = RNA_boolean_get(op->ptr, "flipped");
+ int selOnly = RNA_boolean_get(op->ptr, "selected_mask");
+
+ /* get KeyingSet to use */
+ KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOC_ROT_SCALE_ID);
+
+ /* sanity checks */
+ if (ELEM(NULL, ob, ob->pose))
+ return OPERATOR_CANCELLED;
+
+ if (g_posebuf == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Copy buffer is empty");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* if selOnly option is enabled, if user hasn't selected any bones,
+ * just go back to default behavior to be more in line with other pose tools
+ */
+ if (selOnly) {
+ if (CTX_DATA_COUNT(C, selected_pose_bones) == 0)
+ selOnly = 0;
+ }
+
+ /* Safely merge all of the channels in the buffer pose into any existing pose */
+ for (chan = g_posebuf->chanbase.first; chan; chan = chan->next) {
+ if (chan->flag & POSE_KEY) {
+ /* try to perform paste on this bone */
+ bPoseChannel *pchan = pose_bone_do_paste(ob, chan, selOnly, flip);
+
+ if (pchan) {
+ /* keyframing tagging for successful paste */
+ ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
+ }
+ }
+ }
+
+ /* Update event for pose and deformation children */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* notifiers for updates */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_paste(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Paste Pose";
+ ot->idname = "POSE_OT_paste";
+ ot->description = "Paste the stored pose on to the current pose";
+
+ /* api callbacks */
+ ot->exec = pose_paste_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flag */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "flipped", FALSE, "Flipped on X-Axis", "Paste the stored pose flipped on to current pose");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ RNA_def_boolean(ot->srna, "selected_mask", FALSE, "On Selected Only", "Only paste the stored pose on to selected bones in the current pose");
+}
+
+/* ********************************************** */
+/* Clear Pose Transforms */
+
+/* clear scale of pose-channel */
+static void pchan_clear_scale(bPoseChannel *pchan)
+{
+ if ((pchan->protectflag & OB_LOCK_SCALEX) == 0)
+ pchan->size[0] = 1.0f;
+ if ((pchan->protectflag & OB_LOCK_SCALEY) == 0)
+ pchan->size[1] = 1.0f;
+ if ((pchan->protectflag & OB_LOCK_SCALEZ) == 0)
+ pchan->size[2] = 1.0f;
+}
+
+/* clear location of pose-channel */
+static void pchan_clear_loc(bPoseChannel *pchan)
+{
+ if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
+ pchan->loc[0] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
+ pchan->loc[1] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
+ pchan->loc[2] = 0.0f;
+}
+
+/* clear rotation of pose-channel */
+static void pchan_clear_rot(bPoseChannel *pchan)
+{
+ if (pchan->protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) {
+ /* check if convert to eulers for locking... */
+ if (pchan->protectflag & OB_LOCK_ROT4D) {
+ /* perform clamping on a component by component basis */
+ if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ if ((pchan->protectflag & OB_LOCK_ROTW) == 0)
+ pchan->rotAngle = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
+ pchan->rotAxis[0] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
+ pchan->rotAxis[1] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
+ pchan->rotAxis[2] = 0.0f;
+
+ /* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */
+ if (IS_EQF(pchan->rotAxis[0], pchan->rotAxis[1]) && IS_EQF(pchan->rotAxis[1], pchan->rotAxis[2]))
+ pchan->rotAxis[1] = 1.0f;
+ }
+ else if (pchan->rotmode == ROT_MODE_QUAT) {
+ if ((pchan->protectflag & OB_LOCK_ROTW) == 0)
+ pchan->quat[0] = 1.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
+ pchan->quat[1] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
+ pchan->quat[2] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
+ pchan->quat[3] = 0.0f;
+ }
+ else {
+ /* the flag may have been set for the other modes, so just ignore the extra flag... */
+ if ((pchan->protectflag & OB_LOCK_ROTX) == 0)
+ pchan->eul[0] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTY) == 0)
+ pchan->eul[1] = 0.0f;
+ if ((pchan->protectflag & OB_LOCK_ROTZ) == 0)
+ pchan->eul[2] = 0.0f;
+ }
+ }
+ else {
+ /* perform clamping using euler form (3-components) */
+ float eul[3], oldeul[3], quat1[4] = {0};
+ float qlen = 0.0f;
+
+ if (pchan->rotmode == ROT_MODE_QUAT) {
+ qlen = normalize_qt_qt(quat1, pchan->quat);
+ quat_to_eul(oldeul, quat1);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
+ }
+ else {
+ copy_v3_v3(oldeul, pchan->eul);
+ }
+
+ eul[0] = eul[1] = eul[2] = 0.0f;
+
+ if (pchan->protectflag & OB_LOCK_ROTX)
+ eul[0] = oldeul[0];
+ if (pchan->protectflag & OB_LOCK_ROTY)
+ eul[1] = oldeul[1];
+ if (pchan->protectflag & OB_LOCK_ROTZ)
+ eul[2] = oldeul[2];
+
+ if (pchan->rotmode == ROT_MODE_QUAT) {
+ eul_to_quat(pchan->quat, eul);
+
+ /* restore original quat size */
+ mul_qt_fl(pchan->quat, qlen);
+
+ /* quaternions flip w sign to accumulate rotations correctly */
+ if ((quat1[0] < 0.0f && pchan->quat[0] > 0.0f) || (quat1[0] > 0.0f && pchan->quat[0] < 0.0f)) {
+ mul_qt_fl(pchan->quat, -1.0f);
+ }
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
+ }
+ else {
+ copy_v3_v3(pchan->eul, eul);
+ }
+ }
+ } /* Duplicated in source/blender/editors/object/object_transform.c */
+ else {
+ if (pchan->rotmode == ROT_MODE_QUAT) {
+ unit_qt(pchan->quat);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ /* by default, make rotation of 0 radians around y-axis (roll) */
+ unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
+ }
+ else {
+ zero_v3(pchan->eul);
+ }
+ }
+}
+
+/* clear loc/rot/scale of pose-channel */
+static void pchan_clear_transforms(bPoseChannel *pchan)
+{
+ pchan_clear_loc(pchan);
+ pchan_clear_rot(pchan);
+ pchan_clear_scale(pchan);
+}
+
+/* --------------- */
+
+/* generic exec for clear-pose operators */
+static int pose_clear_transform_generic_exec(bContext *C, wmOperator *op,
+ void (*clear_func)(bPoseChannel *), const char default_ksName[])
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
+ short autokey = 0;
+
+ /* sanity checks */
+ if (ELEM(NULL, clear_func, default_ksName)) {
+ BKE_report(op->reports, RPT_ERROR, "Programming error: missing clear transform function or keying set name");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* only clear relevant transforms for selected bones */
+ CTX_DATA_BEGIN(C, bPoseChannel *, pchan, selected_pose_bones)
+ {
+ /* run provided clearing function */
+ clear_func(pchan);
+
+ /* do auto-keyframing as appropriate */
+ if (autokeyframe_cfra_can_key(scene, &ob->id)) {
+ /* clear any unkeyed tags */
+ if (pchan->bone)
+ pchan->bone->flag &= ~BONE_UNKEYED;
+
+ /* tag for autokeying later */
+ autokey = 1;
+ }
+ else {
+ /* add unkeyed tags */
+ if (pchan->bone)
+ pchan->bone->flag |= BONE_UNKEYED;
+ }
+ }
+ CTX_DATA_END;
+
+ /* perform autokeying on the bones if needed */
+ if (autokey) {
+ /* get KeyingSet to use */
+ KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
+
+ /* insert keyframes */
+ ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+
+ /* now recalculate paths */
+ if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS))
+ ED_pose_recalculate_paths(scene, ob);
+ }
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+
+ /* note, notifier might evolve */
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+/* --------------- */
+
+static int pose_clear_scale_exec(bContext *C, wmOperator *op)
+{
+ return pose_clear_transform_generic_exec(C, op, pchan_clear_scale, ANIM_KS_SCALING_ID);
+}
+
+void POSE_OT_scale_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Pose Scale";
+ ot->idname = "POSE_OT_scale_clear";
+ ot->description = "Reset scaling of selected bones to their default values";
+
+ /* api callbacks */
+ ot->exec = pose_clear_scale_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int pose_clear_rot_exec(bContext *C, wmOperator *op)
+{
+ return pose_clear_transform_generic_exec(C, op, pchan_clear_rot, ANIM_KS_ROTATION_ID);
+}
+
+void POSE_OT_rot_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Pose Rotation";
+ ot->idname = "POSE_OT_rot_clear";
+ ot->description = "Reset rotations of selected bones to their default values";
+
+ /* api callbacks */
+ ot->exec = pose_clear_rot_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int pose_clear_loc_exec(bContext *C, wmOperator *op)
+{
+ return pose_clear_transform_generic_exec(C, op, pchan_clear_loc, ANIM_KS_LOCATION_ID);
+}
+
+void POSE_OT_loc_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Pose Location";
+ ot->idname = "POSE_OT_loc_clear";
+ ot->description = "Reset locations of selected bones to their default values";
+
+ /* api callbacks */
+ ot->exec = pose_clear_loc_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int pose_clear_transforms_exec(bContext *C, wmOperator *op)
+{
+ return pose_clear_transform_generic_exec(C, op, pchan_clear_transforms, ANIM_KS_LOC_ROT_SCALE_ID);
+}
+
+void POSE_OT_transforms_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Pose Transforms";
+ ot->idname = "POSE_OT_transforms_clear";
+ ot->description = "Reset location, rotation, and scaling of selected bones to their default values";
+
+ /* api callbacks */
+ ot->exec = pose_clear_transforms_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ********************************************** */
+/* Clear User Transforms */
+
+static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ float cframe = (float)CFRA;
+ const short only_select = RNA_boolean_get(op->ptr, "only_selected");
+
+ if ((ob->adt) && (ob->adt->action)) {
+ /* XXX: this is just like this to avoid contaminating anything else;
+ * just pose values should change, so this should be fine
+ */
+ bPose *dummyPose = NULL;
+ Object workob = {{0}};
+ bPoseChannel *pchan;
+
+ /* execute animation step for current frame using a dummy copy of the pose */
+ BKE_pose_copy_data(&dummyPose, ob->pose, 0);
+
+ BLI_strncpy(workob.id.name, "OB<ClearTfmWorkOb>", sizeof(workob.id.name));
+ workob.type = OB_ARMATURE;
+ workob.data = ob->data;
+ workob.adt = ob->adt;
+ workob.pose = dummyPose;
+
+ BKE_animsys_evaluate_animdata(scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM);
+
+ /* copy back values, but on selected bones only */
+ for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
+ pose_bone_do_paste(ob, pchan, only_select, 0);
+ }
+
+ /* free temp data - free manually as was copied without constraints */
+ for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->prop) {
+ IDP_FreeProperty(pchan->prop);
+ MEM_freeN(pchan->prop);
+ }
+ }
+
+ /* was copied without constraints */
+ BLI_freelistN(&dummyPose->chanbase);
+ MEM_freeN(dummyPose);
+ }
+ else {
+ /* no animation, so just reset whole pose to rest pose
+ * (cannot just restore for selected though)
+ */
+ BKE_pose_rest(ob->pose);
+ }
+
+ /* notifiers and updates */
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_user_transforms_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear User Transforms";
+ ot->idname = "POSE_OT_user_transforms_clear";
+ ot->description = "Reset pose on selected bones to keyframed state";
+
+ /* callbacks */
+ ot->exec = pose_clear_user_transforms_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "only_selected", TRUE, "Only Selected", "Only visible/selected bones");
+}
diff --git a/source/blender/editors/armature/poseUtils.c b/source/blender/editors/armature/pose_utils.c
index f3c32399ad6..a5e51ccf32a 100644
--- a/source/blender/editors/armature/poseUtils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -23,25 +23,14 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/editors/armature/poseUtils.c
+/** \file blender/editors/armature/pose_utils.c
* \ingroup edarmature
*/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <string.h>
-#include <math.h>
-#include <float.h>
-
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
-#include "BLI_dynstr.h"
-#include "BLI_dlrbTree.h"
-#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c
deleted file mode 100644
index c7d1e428355..00000000000
--- a/source/blender/editors/armature/poseobject.c
+++ /dev/null
@@ -1,2364 +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.
- *
- * Contributor(s): Ton Roosendaal, Blender Foundation '05, full recode.
- * Joshua Leung
- *
- * ***** END GPL LICENSE BLOCK *****
- * support for animation modes - Reevan McKay
- */
-
-/** \file blender/editors/armature/poseobject.c
- * \ingroup edarmature
- */
-
-
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_dynstr.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_constraint_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
-
-#include "BKE_animsys.h"
-#include "BKE_anim.h"
-#include "BKE_idprop.h"
-#include "BKE_action.h"
-#include "BKE_armature.h"
-#include "BKE_context.h"
-#include "BKE_constraint.h"
-#include "BKE_deform.h"
-#include "BKE_depsgraph.h"
-#include "BKE_fcurve.h"
-#include "BKE_modifier.h"
-#include "BKE_object.h"
-#include "BKE_report.h"
-
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-#include "RNA_enum_types.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_armature.h"
-#include "ED_keyframing.h"
-#include "ED_mesh.h"
-#include "ED_screen.h"
-#include "ED_object.h"
-#include "ED_util.h" /* clipboard */
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "armature_intern.h"
-
-/* matches logic with ED_operator_posemode_context() */
-Object *ED_pose_object_from_context(bContext *C)
-{
- ScrArea *sa = CTX_wm_area(C);
- Object *ob;
-
- /* since this call may also be used from the buttons window, we need to check for where to get the object */
- if (sa && sa->spacetype == SPACE_BUTS) {
- ob = ED_object_context(C);
- }
- else {
- ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- }
-
- return ob;
-}
-
-/* This function is used to process the necessary updates for */
-void ED_armature_enter_posemode(bContext *C, Base *base)
-{
- ReportList *reports = CTX_wm_reports(C);
- Object *ob = base->object;
-
- if (ob->id.lib) {
- BKE_report(reports, RPT_WARNING, "Cannot pose libdata");
- return;
- }
-
- switch (ob->type) {
- case OB_ARMATURE:
- ob->restore_mode = ob->mode;
- ob->mode |= OB_MODE_POSE;
-
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL);
-
- break;
- default:
- return;
- }
-
- /* XXX: disabled as this would otherwise cause a nasty loop... */
- //ED_object_toggle_modes(C, ob->mode);
-}
-
-void ED_armature_exit_posemode(bContext *C, Base *base)
-{
- if (base) {
- Object *ob = base->object;
-
- ob->restore_mode = ob->mode;
- ob->mode &= ~OB_MODE_POSE;
-
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
- }
-}
-
-/* if a selected or active bone is protected, throw error (oonly if warn == 1) and return 1 */
-/* only_selected == 1: the active bone is allowed to be protected */
-#if 0 /* UNUSED 2.5 */
-static short pose_has_protected_selected(Object *ob, short warn)
-{
- /* check protection */
- if (ob->proxy) {
- bPoseChannel *pchan;
- bArmature *arm = ob->data;
-
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone && (pchan->bone->layer & arm->layer)) {
- if (pchan->bone->layer & arm->layer_protected) {
- if (pchan->bone->flag & BONE_SELECTED)
- break;
- }
- }
- }
- if (pchan) {
- if (warn) error("Cannot change Proxy protected bones");
- return 1;
- }
- }
- return 0;
-}
-#endif
-
-/* only for real IK, not for auto-IK */
-static int pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan, int level)
-{
- bConstraint *con;
- Bone *bone;
-
- /* No need to check if constraint is active (has influence),
- * since all constraints with CONSTRAINT_IK_AUTO are active */
- for (con = pchan->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
- bKinematicConstraint *data = con->data;
- if (data->rootbone == 0 || data->rootbone > level) {
- if ((data->flag & CONSTRAINT_IK_AUTO) == 0)
- return 1;
- }
- }
- }
- for (bone = pchan->bone->childbase.first; bone; bone = bone->next) {
- pchan = BKE_pose_channel_find_name(ob->pose, bone->name);
- if (pchan && pose_channel_in_IK_chain(ob, pchan, level + 1))
- return 1;
- }
- return 0;
-}
-
-int ED_pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan)
-{
- return pose_channel_in_IK_chain(ob, pchan, 0);
-}
-
-/* ********************************************** */
-/* Motion Paths */
-
-/* For the object with pose/action: update paths for those that have got them
- * This should selectively update paths that exist...
- *
- * To be called from various tools that do incremental updates
- */
-void ED_pose_recalculate_paths(Scene *scene, Object *ob)
-{
- ListBase targets = {NULL, NULL};
-
- /* set flag to force recalc, then grab the relevant bones to target */
- ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS;
- animviz_get_object_motionpaths(ob, &targets);
-
- /* recalculate paths, then free */
- animviz_calc_motionpaths(scene, &targets);
- BLI_freelistN(&targets);
-}
-
-
-/* show popup to determine settings */
-static int pose_calculate_paths_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
-
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- /* set default settings from existing/stored settings */
- {
- bAnimVizSettings *avs = &ob->pose->avs;
- PointerRNA avs_ptr;
-
- RNA_int_set(op->ptr, "start_frame", avs->path_sf);
- RNA_int_set(op->ptr, "end_frame", avs->path_ef);
-
- RNA_pointer_create(NULL, &RNA_AnimVizMotionPaths, avs, &avs_ptr);
- RNA_enum_set(op->ptr, "bake_location", RNA_enum_get(&avs_ptr, "bake_location"));
- }
-
- /* show popup dialog to allow editing of range... */
- // FIXME: hardcoded dimensions here are just arbitrary
- return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 10 * UI_UNIT_Y);
-}
-
-/* For the object with pose/action: create path curves for selected bones
- * This recalculates the WHOLE path within the pchan->pathsf and pchan->pathef range
- */
-static int pose_calculate_paths_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- Scene *scene = CTX_data_scene(C);
-
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- /* grab baking settings from operator settings */
- {
- bAnimVizSettings *avs = &ob->pose->avs;
- PointerRNA avs_ptr;
-
- avs->path_sf = RNA_int_get(op->ptr, "start_frame");
- avs->path_ef = RNA_int_get(op->ptr, "end_frame");
-
- RNA_pointer_create(NULL, &RNA_AnimVizMotionPaths, avs, &avs_ptr);
- RNA_enum_set(&avs_ptr, "bake_location", RNA_enum_get(op->ptr, "bake_location"));
- }
-
- /* set up path data for bones being calculated */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- /* verify makes sure that the selected bone has a bone with the appropriate settings */
- animviz_verify_motionpaths(op->reports, scene, ob, pchan);
- }
- CTX_DATA_END;
-
- /* calculate the bones that now have motionpaths... */
- /* TODO: only make for the selected bones? */
- ED_pose_recalculate_paths(scene, ob);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_paths_calculate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Calculate Bone Paths";
- ot->idname = "POSE_OT_paths_calculate";
- ot->description = "Calculate paths for the selected bones";
-
- /* api callbacks */
- ot->invoke = pose_calculate_paths_invoke;
- ot->exec = pose_calculate_paths_exec;
- ot->poll = ED_operator_posemode_exclusive;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_int(ot->srna, "start_frame", 1, MINAFRAME, MAXFRAME, "Start",
- "First frame to calculate bone paths on", MINFRAME, MAXFRAME / 2.0);
- 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,
- "Bake Location",
- "Which point on the bones is used when calculating paths");
-}
-
-/* --------- */
-
-static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- Scene *scene = CTX_data_scene(C);
-
- if (ELEM(NULL, ob, scene))
- return OPERATOR_CANCELLED;
-
- /* calculate the bones that now have motionpaths... */
- /* TODO: only make for the selected bones? */
- ED_pose_recalculate_paths(scene, ob);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_paths_update(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Update Bone Paths";
- ot->idname = "POSE_OT_paths_update";
- ot->description = "Recalculate paths for bones that already have them";
-
- /* 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 */
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* --------- */
-
-/* for the object with pose/action: clear path curves for selected bones only */
-static void ED_pose_clear_paths(Object *ob)
-{
- bPoseChannel *pchan;
- short skipped = 0;
-
- if (ELEM(NULL, ob, ob->pose))
- return;
-
- /* free the motionpath blocks, but also take note of whether we skipped some... */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->mpath) {
- if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
- animviz_free_motionpath(pchan->mpath);
- pchan->mpath = NULL;
- }
- else
- skipped = 1;
- }
- }
-
- /* if we didn't skip any, we shouldn't have any paths left */
- if (skipped == 0)
- ob->pose->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS;
-}
-
-/* operator callback for this */
-static int pose_clear_paths_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
-
- /* 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);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-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";
-
- /* api callbacks */
- ot->exec = pose_clear_paths_exec;
- ot->poll = ED_operator_posemode_exclusive;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ******************* Select Constraint Target Operator ************* */
-
-static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (bArmature *)ob->data;
- bConstraint *con;
- int found = 0;
-
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- if (pchan->bone->flag & BONE_SELECTED) {
- for (con = pchan->constraints.first; con; con = con->next) {
- bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
- ListBase targets = {NULL, NULL};
- bConstraintTarget *ct;
-
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- for (ct = targets.first; ct; ct = ct->next) {
- if ((ct->tar == ob) && (ct->subtarget[0])) {
- bPoseChannel *pchanc = BKE_pose_channel_find_name(ob->pose, ct->subtarget);
- if ((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) {
- pchanc->bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
- found = 1;
- }
- }
- }
-
- if (cti->flush_constraint_targets)
- cti->flush_constraint_targets(con, &targets, 1);
- }
- }
- }
- }
- CTX_DATA_END;
-
- if (!found)
- return OPERATOR_CANCELLED;
-
- /* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_select_constraint_target(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Constraint Target";
- ot->idname = "POSE_OT_select_constraint_target";
- ot->description = "Select bones used as targets for the currently selected bones";
-
- /* api callbacks */
- ot->exec = pose_select_constraint_target_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ******************* select hierarchy operator ************* */
-
-static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = ob->data;
- Bone *curbone, *pabone, *chbone;
- int direction = RNA_enum_get(op->ptr, "direction");
- int add_to_sel = RNA_boolean_get(op->ptr, "extend");
- int found = 0;
-
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- curbone = pchan->bone;
-
- if ((curbone->flag & BONE_UNSELECTABLE) == 0) {
- if (curbone == arm->act_bone) {
- if (direction == BONE_SELECT_PARENT) {
- if (pchan->parent == NULL) continue;
- else pabone = pchan->parent->bone;
-
- if (PBONE_SELECTABLE(arm, pabone)) {
- if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
- pabone->flag |= BONE_SELECTED;
- arm->act_bone = pabone;
-
- found = 1;
- break;
- }
- }
- else { /* direction == BONE_SELECT_CHILD */
- /* the child member is only assigned to connected bones, see [#30340] */
-#if 0
- if (pchan->child == NULL) continue;
- else chbone = pchan->child->bone;
-#else
- /* instead. find _any_ visible child bone, using the first one is a little arbitrary - campbell */
- chbone = pchan->child ? pchan->child->bone : NULL;
- if (chbone == NULL) {
- bPoseChannel *pchan_child;
-
- for (pchan_child = ob->pose->chanbase.first; pchan_child; pchan_child = pchan_child->next) {
- /* possible we have multiple children, some invisible */
- if (PBONE_SELECTABLE(arm, pchan_child->bone)) {
- if (pchan_child->parent == pchan) {
- chbone = pchan_child->bone;
- break;
- }
- }
- }
- }
-
- if (chbone == NULL) continue;
-#endif
-
- if (PBONE_SELECTABLE(arm, chbone)) {
- if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
- chbone->flag |= BONE_SELECTED;
- arm->act_bone = chbone;
-
- found = 1;
- break;
- }
- }
- }
- }
- }
- CTX_DATA_END;
-
- if (found == 0)
- return OPERATOR_CANCELLED;
-
- /* updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_select_hierarchy(wmOperatorType *ot)
-{
- static EnumPropertyItem direction_items[] = {
- {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
- {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Select Hierarchy";
- ot->idname = "POSE_OT_select_hierarchy";
- ot->description = "Select immediate parent/children of selected bones";
-
- /* api callbacks */
- ot->exec = pose_select_hierarchy_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* props */
- ot->prop = RNA_def_enum(ot->srna, "direction", direction_items, BONE_SELECT_PARENT, "Direction", "");
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
-}
-
-/* ******************* select grouped operator ************* */
-
-static short pose_select_same_group(bContext *C, Object *ob, short extend)
-{
- bArmature *arm = (ob) ? ob->data : NULL;
- bPose *pose = (ob) ? ob->pose : NULL;
- char *group_flags;
- int numGroups = 0;
- short changed = 0, tagged = 0;
-
- /* sanity checks */
- if (ELEM3(NULL, ob, pose, arm))
- return 0;
-
- /* count the number of groups */
- numGroups = BLI_countlist(&pose->agroups);
- if (numGroups == 0)
- return 0;
-
- /* alloc a small array to keep track of the groups to use
- * - each cell stores on/off state for whether group should be used
- * - size is (numGroups + 1), since (index = 0) is used for no-group
- */
- group_flags = MEM_callocN(numGroups + 1, "pose_select_same_group");
-
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- /* keep track of group as group to use later? */
- if (pchan->bone->flag & BONE_SELECTED) {
- group_flags[pchan->agrp_index] = 1;
- tagged = 1;
- }
-
- /* deselect all bones before selecting new ones? */
- if ((extend == 0) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0)
- pchan->bone->flag &= ~BONE_SELECTED;
- }
- CTX_DATA_END;
-
- /* small optimization: only loop through bones a second time if there are any groups tagged */
- if (tagged) {
- /* only if group matches (and is not selected or current bone) */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
- /* check if the group used by this bone is counted */
- if (group_flags[pchan->agrp_index]) {
- pchan->bone->flag |= BONE_SELECTED;
- changed = 1;
- }
- }
- }
- CTX_DATA_END;
- }
-
- /* free temp info */
- MEM_freeN(group_flags);
-
- return changed;
-}
-
-static short pose_select_same_layer(bContext *C, Object *ob, short extend)
-{
- bPose *pose = (ob) ? ob->pose : NULL;
- bArmature *arm = (ob) ? ob->data : NULL;
- short changed = 0;
- int layers = 0;
-
- if (ELEM3(NULL, ob, pose, arm))
- return 0;
-
- /* figure out what bones are selected */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- /* keep track of layers to use later? */
- if (pchan->bone->flag & BONE_SELECTED)
- layers |= pchan->bone->layer;
-
- /* deselect all bones before selecting new ones? */
- if ((extend == 0) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0)
- pchan->bone->flag &= ~BONE_SELECTED;
- }
- CTX_DATA_END;
- if (layers == 0)
- return 0;
-
- /* select bones that are on same layers as layers flag */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- /* if bone is on a suitable layer, and the bone can have its selection changed, select it */
- if ((layers & pchan->bone->layer) && (pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
- pchan->bone->flag |= BONE_SELECTED;
- changed = 1;
- }
- }
- CTX_DATA_END;
-
- return changed;
-}
-
-static int pose_select_same_keyingset(bContext *C, Object *ob, short extend)
-{
- KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C));
- KS_Path *ksp;
-
- bArmature *arm = (ob) ? ob->data : NULL;
- bPose *pose = (ob) ? ob->pose : NULL;
- short changed = 0;
-
- /* sanity checks: validate Keying Set and object */
- if ((ks == NULL) || (ANIM_validate_keyingset(C, NULL, ks) != 0))
- return 0;
-
- if (ELEM3(NULL, ob, pose, arm))
- return 0;
-
- /* if not extending selection, deselect all selected first */
- if (extend == 0) {
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)
- pchan->bone->flag &= ~BONE_SELECTED;
- }
- CTX_DATA_END;
- }
-
- /* iterate over elements in the Keying Set, setting selection depending on whether
- * that bone is visible or not...
- */
- for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
- /* only items related to this object will be relevant */
- if ((ksp->id == &ob->id) && (ksp->rna_path != NULL)) {
- if (strstr(ksp->rna_path, "bones")) {
- char *boneName = BLI_str_quoted_substrN(ksp->rna_path, "bones[");
-
- if (boneName) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(pose, boneName);
-
- if (pchan) {
- /* select if bone is visible and can be affected */
- if (PBONE_SELECTABLE(arm, pchan->bone)) {
- pchan->bone->flag |= BONE_SELECTED;
- changed = 1;
- }
- }
-
- /* free temp memory */
- MEM_freeN(boneName);
- }
- }
- }
- }
-
- return changed;
-}
-
-static int pose_select_grouped_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (bArmature *)ob->data;
- short extend = RNA_boolean_get(op->ptr, "extend");
- short changed = 0;
-
- /* sanity check */
- if (ob->pose == NULL)
- return OPERATOR_CANCELLED;
-
- /* selection types
- * NOTE: for the order of these, see the enum in POSE_OT_select_grouped()
- */
- switch (RNA_enum_get(op->ptr, "type")) {
- case 1: /* group */
- changed = pose_select_same_group(C, ob, extend);
- break;
- case 2: /* Keying Set */
- changed = pose_select_same_keyingset(C, ob, extend);
- break;
- default: /* layer */
- changed = pose_select_same_layer(C, ob, extend);
- break;
- }
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* mask modifier ('armature' mode), etc. */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- }
-
- /* report done status */
- if (changed)
- return OPERATOR_FINISHED;
- else
- return OPERATOR_CANCELLED;
-}
-
-void POSE_OT_select_grouped(wmOperatorType *ot)
-{
- static EnumPropertyItem prop_select_grouped_types[] = {
- {0, "LAYER", 0, "Layer", "Shared layers"},
- {1, "GROUP", 0, "Group", "Shared group"},
- {2, "KEYINGSET", 0, "Keying Set", "All bones affected by active Keying Set"},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Select Grouped";
- ot->description = "Select all visible bones grouped by similar properties";
- ot->idname = "POSE_OT_select_grouped";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = pose_select_grouped_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
- ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
-}
-
-
-/* ********************************************** */
-
-/* context active object, or weightpainted object with armature in posemode */
-static int pose_bone_flip_active_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob_act = CTX_data_active_object(C);
- Object *ob = BKE_object_pose_armature_get(ob_act);
-
- if (ob && (ob->mode & OB_MODE_POSE)) {
- bArmature *arm = ob->data;
-
- if (arm->act_bone) {
- bPoseChannel *pchanf;
- char name[MAXBONENAME];
- flip_side_name(name, arm->act_bone->name, TRUE);
-
- pchanf = BKE_pose_channel_find_name(ob->pose, name);
- if (pchanf && pchanf->bone != arm->act_bone) {
- arm->act_bone->flag &= ~BONE_SELECTED;
- pchanf->bone->flag |= BONE_SELECTED;
-
- arm->act_bone = pchanf->bone;
-
- /* in weightpaint we select the associated vertex group too */
- if (ob_act->mode & OB_MODE_WEIGHT_PAINT) {
- ED_vgroup_select_by_name(ob_act, name);
- DAG_id_tag_update(&ob_act->id, OB_RECALC_DATA);
- }
-
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
-
- return OPERATOR_FINISHED;
- }
- }
- }
-
- return OPERATOR_CANCELLED;
-}
-
-void POSE_OT_select_flip_active(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Flip Selected Active Bone";
- ot->idname = "POSE_OT_select_flip_active";
- ot->description = "Activate the bone with a flipped name";
-
- /* api callbacks */
- ot->exec = pose_bone_flip_active_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-/* ********************************************** */
-#if 0 /* UNUSED 2.5 */
-static void pose_copy_menu(Scene *scene)
-{
- Object *obedit = scene->obedit; // XXX context
- Object *ob = OBACT;
- bArmature *arm;
- bPoseChannel *pchan, *pchanact;
- short nr = 0;
- int i = 0;
-
- /* paranoia checks */
- if (ELEM(NULL, ob, ob->pose)) return;
- if ((ob == obedit) || (ob->mode & OB_MODE_POSE) == 0) return;
-
- pchan = BKE_pose_channel_active(ob);
-
- if (pchan == NULL) return;
- pchanact = pchan;
- arm = ob->data;
-
- /* if proxy-protected bones selected, some things (such as locks + displays) shouldn't be changeable,
- * but for constraints (just add local constraints)
- */
- if (pose_has_protected_selected(ob, 0)) {
- i = BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
- if (i < 25)
- nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|Constraints... %x5");
- else
- nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4");
- }
- else {
- i = BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
- if (i < 25)
- nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|Constraints... %x5|%l|Transform Locks %x6|IK Limits %x7|Bone Shape %x8");
- else
- nr = pupmenu("Copy Pose Attributes %t|Local Location %x1|Local Rotation %x2|Local Size %x3|%l|Visual Location %x9|Visual Rotation %x10|Visual Size %x11|%l|Constraints (All) %x4|%l|Transform Locks %x6|IK Limits %x7|Bone Shape %x8");
- }
-
- if (nr <= 0)
- return;
-
- if (nr != 5) {
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((arm->layer & pchan->bone->layer) &&
- (pchan->bone->flag & BONE_SELECTED) &&
- (pchan != pchanact) )
- {
- switch (nr) {
- case 1: /* Local Location */
- copy_v3_v3(pchan->loc, pchanact->loc);
- break;
- case 2: /* Local Rotation */
- copy_qt_qt(pchan->quat, pchanact->quat);
- copy_v3_v3(pchan->eul, pchanact->eul);
- break;
- case 3: /* Local Size */
- copy_v3_v3(pchan->size, pchanact->size);
- break;
- case 4: /* All Constraints */
- {
- ListBase tmp_constraints = {NULL, NULL};
-
- /* copy constraints to tmpbase and apply 'local' tags before
- * appending to list of constraints for this channel
- */
- BKE_copy_constraints(&tmp_constraints, &pchanact->constraints, TRUE);
- if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) {
- bConstraint *con;
-
- /* add proxy-local tags */
- for (con = tmp_constraints.first; con; con = con->next)
- con->flag |= CONSTRAINT_PROXY_LOCAL;
- }
- BLI_movelisttolist(&pchan->constraints, &tmp_constraints);
-
- /* update flags (need to add here, not just copy) */
- pchan->constflag |= pchanact->constflag;
-
- if (ob->pose)
- ob->pose->flag |= POSE_RECALC;
- }
- break;
- case 6: /* Transform Locks */
- pchan->protectflag = pchanact->protectflag;
- break;
- case 7: /* IK (DOF) settings */
- {
- pchan->ikflag = pchanact->ikflag;
- copy_v3_v3(pchan->limitmin, pchanact->limitmin);
- copy_v3_v3(pchan->limitmax, pchanact->limitmax);
- copy_v3_v3(pchan->stiffness, pchanact->stiffness);
- pchan->ikstretch = pchanact->ikstretch;
- pchan->ikrotweight = pchanact->ikrotweight;
- pchan->iklinweight = pchanact->iklinweight;
- }
- break;
- case 8: /* Custom Bone Shape */
- pchan->custom = pchanact->custom;
- break;
- case 9: /* Visual Location */
- BKE_armature_loc_pose_to_bone(pchan, pchanact->pose_mat[3], pchan->loc);
- break;
- case 10: /* Visual Rotation */
- {
- float delta_mat[4][4];
-
- BKE_armature_mat_pose_to_bone(pchan, pchanact->pose_mat, delta_mat);
-
- if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- float tmp_quat[4];
-
- /* need to convert to quat first (in temp var)... */
- mat4_to_quat(tmp_quat, delta_mat);
- quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, tmp_quat);
- }
- else if (pchan->rotmode == ROT_MODE_QUAT)
- mat4_to_quat(pchan->quat, delta_mat);
- else
- mat4_to_eulO(pchan->eul, pchan->rotmode, delta_mat);
- }
- break;
- case 11: /* Visual Size */
- {
- float delta_mat[4][4], size[4];
-
- BKE_armature_mat_pose_to_bone(pchan, pchanact->pose_mat, delta_mat);
- mat4_to_size(size, delta_mat);
- copy_v3_v3(pchan->size, size);
- }
- }
- }
- }
- }
- else { /* constraints, optional (note: max we can have is 24 constraints) */
- bConstraint *con, *con_back;
- int const_toggle[24] = {0}; /* XXX, initialize as 0 to quiet errors */
- ListBase const_copy = {NULL, NULL};
-
- BLI_duplicatelist(&const_copy, &(pchanact->constraints));
-
- /* build the puplist of constraints */
- for (con = pchanact->constraints.first, i = 0; con; con = con->next, i++) {
- const_toggle[i] = 1;
-// add_numbut(i, TOG|INT, con->name, 0, 0, &(const_toggle[i]), "");
- }
-
-// if (!do_clever_numbuts("Select Constraints", i, REDRAW)) {
-// BLI_freelistN(&const_copy);
-// return;
-// }
-
- /* now build a new listbase from the options selected */
- for (i = 0, con = const_copy.first; con; i++) {
- /* if not selected, free/remove it from the list */
- if (!const_toggle[i]) {
- con_back = con->next;
- BLI_freelinkN(&const_copy, con);
- con = con_back;
- }
- else
- con = con->next;
- }
-
- /* Copy the temo listbase to the selected posebones */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((arm->layer & pchan->bone->layer) &&
- (pchan->bone->flag & BONE_SELECTED) &&
- (pchan != pchanact) )
- {
- ListBase tmp_constraints = {NULL, NULL};
-
- /* copy constraints to tmpbase and apply 'local' tags before
- * appending to list of constraints for this channel
- */
- BKE_copy_constraints(&tmp_constraints, &const_copy, TRUE);
- if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) {
- /* add proxy-local tags */
- for (con = tmp_constraints.first; con; con = con->next)
- con->flag |= CONSTRAINT_PROXY_LOCAL;
- }
- BLI_movelisttolist(&pchan->constraints, &tmp_constraints);
-
- /* update flags (need to add here, not just copy) */
- pchan->constflag |= pchanact->constflag;
- }
- }
- BLI_freelistN(&const_copy);
- BKE_pose_update_constraint_flags(ob->pose); /* we could work out the flags but its simpler to do this */
-
- if (ob->pose)
- ob->pose->flag |= POSE_RECALC;
- }
-
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA); // and all its relations
-
- BIF_undo_push("Copy Pose Attributes");
-
-}
-#endif
-
-/* ******************** copy/paste pose ********************** */
-
-/* Global copy/paste buffer for pose - cleared on start/end session + before every copy operation */
-static bPose *g_posebuf = NULL;
-
-void ED_clipboard_posebuf_free(void)
-{
- if (g_posebuf) {
- bPoseChannel *pchan;
-
- for (pchan = g_posebuf->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->prop) {
- IDP_FreeProperty(pchan->prop);
- MEM_freeN(pchan->prop);
- }
- }
-
- /* was copied without constraints */
- BLI_freelistN(&g_posebuf->chanbase);
- MEM_freeN(g_posebuf);
- }
-
- g_posebuf = NULL;
-}
-
-/* This function is used to indicate that a bone is selected
- * and needs to be included in copy buffer (used to be for inserting keys)
- */
-static void set_pose_keys(Object *ob)
-{
- bArmature *arm = ob->data;
- bPoseChannel *chan;
-
- if (ob->pose) {
- for (chan = ob->pose->chanbase.first; chan; chan = chan->next) {
- Bone *bone = chan->bone;
- if ((bone) && (bone->flag & BONE_SELECTED) && (arm->layer & bone->layer))
- chan->flag |= POSE_KEY;
- else
- chan->flag &= ~POSE_KEY;
- }
- }
-}
-
-/* perform paste pose, for a single bone
- * < ob: object where bone to paste to lives
- * < chan: bone that pose to paste comes from
- * < selOnly: only paste on selected bones
- * < flip: flip on x-axis
- *
- * > returns: whether the bone that we pasted to if we succeeded
- */
-static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, short selOnly, short flip)
-{
- bPoseChannel *pchan;
- char name[MAXBONENAME];
- short paste_ok;
-
- /* get the name - if flipping, we must flip this first */
- if (flip)
- flip_side_name(name, chan->name, 0); /* 0 = don't strip off number extensions */
- else
- BLI_strncpy(name, chan->name, sizeof(name));
-
- /* only copy when:
- * 1) channel exists - poses are not meant to add random channels to anymore
- * 2) if selection-masking is on, channel is selected - only selected bones get pasted on, allowing making both sides symmetrical
- */
- pchan = BKE_pose_channel_find_name(ob->pose, name);
-
- if (selOnly)
- paste_ok = ((pchan) && (pchan->bone->flag & BONE_SELECTED));
- else
- paste_ok = ((pchan != NULL));
-
- /* continue? */
- if (paste_ok) {
- /* only loc rot size
- * - only copies transform info for the pose
- */
- copy_v3_v3(pchan->loc, chan->loc);
- copy_v3_v3(pchan->size, chan->size);
- pchan->flag = chan->flag;
-
- /* check if rotation modes are compatible (i.e. do they need any conversions) */
- if (pchan->rotmode == chan->rotmode) {
- /* copy the type of rotation in use */
- if (pchan->rotmode > 0) {
- copy_v3_v3(pchan->eul, chan->eul);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- copy_v3_v3(pchan->rotAxis, chan->rotAxis);
- pchan->rotAngle = chan->rotAngle;
- }
- else {
- copy_qt_qt(pchan->quat, chan->quat);
- }
- }
- else if (pchan->rotmode > 0) {
- /* quat/axis-angle to euler */
- if (chan->rotmode == ROT_MODE_AXISANGLE)
- axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle);
- else
- quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- /* quat/euler to axis angle */
- if (chan->rotmode > 0)
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
- else
- quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
- }
- else {
- /* euler/axis-angle to quat */
- if (chan->rotmode > 0)
- eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
- else
- axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
- }
-
- /* paste flipped pose? */
- if (flip) {
- pchan->loc[0] *= -1;
-
- /* has to be done as eulers... */
- if (pchan->rotmode > 0) {
- pchan->eul[1] *= -1;
- pchan->eul[2] *= -1;
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- float eul[3];
-
- axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
- eul[1] *= -1;
- eul[2] *= -1;
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
- }
- else {
- float eul[3];
-
- normalize_qt(pchan->quat);
- quat_to_eul(eul, pchan->quat);
- eul[1] *= -1;
- eul[2] *= -1;
- eul_to_quat(pchan->quat, eul);
- }
- }
-
- /* ID properties */
- if (chan->prop) {
- if (pchan->prop) {
- /* if we have existing properties on a bone, just copy over the values of
- * matching properties (i.e. ones which will have some impact) on to the
- * target instead of just blinding replacing all [
- */
- IDP_SyncGroupValues(pchan->prop, chan->prop);
- }
- else {
- /* no existing properties, so assume that we want copies too? */
- pchan->prop = IDP_CopyProperty(chan->prop);
- }
- }
- }
-
- /* return whether paste went ahead */
- return pchan;
-}
-
-/* ---- */
-
-static int pose_copy_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
-
- /* sanity checking */
- if (ELEM(NULL, ob, ob->pose)) {
- BKE_report(op->reports, RPT_ERROR, "No pose to copy");
- return OPERATOR_CANCELLED;
- }
-
- /* free existing pose buffer */
- ED_clipboard_posebuf_free();
-
- /* sets chan->flag to POSE_KEY if bone selected, then copy those bones to the buffer */
- set_pose_keys(ob);
- BKE_pose_copy_data(&g_posebuf, ob->pose, 0);
-
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_copy(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Copy Pose";
- ot->idname = "POSE_OT_copy";
- ot->description = "Copies the current pose of the selected bones to copy/paste buffer";
-
- /* api callbacks */
- ot->exec = pose_copy_exec;
- ot->poll = ED_operator_posemode;
-
- /* flag */
- ot->flag = OPTYPE_REGISTER;
-}
-
-/* ---- */
-
-static int pose_paste_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- Scene *scene = CTX_data_scene(C);
- bPoseChannel *chan;
- int flip = RNA_boolean_get(op->ptr, "flipped");
- int selOnly = RNA_boolean_get(op->ptr, "selected_mask");
-
- /* get KeyingSet to use */
- KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOC_ROT_SCALE_ID);
-
- /* sanity checks */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- if (g_posebuf == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Copy buffer is empty");
- return OPERATOR_CANCELLED;
- }
-
- /* if selOnly option is enabled, if user hasn't selected any bones,
- * just go back to default behavior to be more in line with other pose tools
- */
- if (selOnly) {
- if (CTX_DATA_COUNT(C, selected_pose_bones) == 0)
- selOnly = 0;
- }
-
- /* Safely merge all of the channels in the buffer pose into any existing pose */
- for (chan = g_posebuf->chanbase.first; chan; chan = chan->next) {
- if (chan->flag & POSE_KEY) {
- /* try to perform paste on this bone */
- bPoseChannel *pchan = pose_bone_do_paste(ob, chan, selOnly, flip);
-
- if (pchan) {
- /* keyframing tagging for successful paste */
- ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
- }
- }
- }
-
- /* Update event for pose and deformation children */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_paste(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Paste Pose";
- ot->idname = "POSE_OT_paste";
- ot->description = "Paste the stored pose on to the current pose";
-
- /* api callbacks */
- ot->exec = pose_paste_exec;
- ot->poll = ED_operator_posemode;
-
- /* flag */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- prop = RNA_def_boolean(ot->srna, "flipped", FALSE, "Flipped on X-Axis", "Paste the stored pose flipped on to current pose");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- RNA_def_boolean(ot->srna, "selected_mask", FALSE, "On Selected Only", "Only paste the stored pose on to selected bones in the current pose");
-}
-
-/* ********************************************** */
-/* Bone Groups */
-
-static int pose_group_add_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_pose_object_from_context(C);
-
- /* only continue if there's an object */
- if (ob == NULL)
- return OPERATOR_CANCELLED;
-
- /* for now, just call the API function for this */
- BKE_pose_add_group(ob);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_group_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Bone Group";
- ot->idname = "POSE_OT_group_add";
- ot->description = "Add a new bone group";
-
- /* api callbacks */
- ot->exec = pose_group_add_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-
-static int pose_group_remove_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_pose_object_from_context(C);
-
- /* only continue if there's an object */
- if (ob == NULL)
- return OPERATOR_CANCELLED;
-
- /* for now, just call the API function for this */
- BKE_pose_remove_group(ob);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_group_remove(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove Bone Group";
- ot->idname = "POSE_OT_group_remove";
- ot->description = "Remove the active bone group";
-
- /* api callbacks */
- ot->exec = pose_group_remove_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ------------ */
-
-/* invoke callback which presents a list of bone-groups for the user to choose from */
-static int pose_groups_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
-{
- Object *ob = ED_pose_object_from_context(C);
- bPose *pose;
-
- uiPopupMenu *pup;
- uiLayout *layout;
- bActionGroup *grp;
- int i;
-
- /* only continue if there's an object, and a pose there too */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
- pose = ob->pose;
-
- /* if there's no active group (or active is invalid), create a new menu to find it */
- if (pose->active_group <= 0) {
- /* create a new menu, and start populating it with group names */
- pup = uiPupMenuBegin(C, op->type->name, ICON_NONE);
- layout = uiPupMenuLayout(pup);
-
- /* special entry - allow to create new group, then use that
- * (not to be used for removing though)
- */
- if (strstr(op->idname, "assign")) {
- uiItemIntO(layout, "New Group", ICON_NONE, op->idname, "type", 0);
- uiItemS(layout);
- }
-
- /* add entries for each group */
- for (grp = pose->agroups.first, i = 1; grp; grp = grp->next, i++)
- uiItemIntO(layout, grp->name, ICON_NONE, op->idname, "type", i);
-
- /* finish building the menu, and process it (should result in calling self again) */
- uiPupMenuEnd(C, pup);
-
- return OPERATOR_CANCELLED;
- }
- else {
- /* just use the active group index, and call the exec callback for the calling operator */
- RNA_int_set(op->ptr, "type", pose->active_group);
- return op->type->exec(C, op);
- }
-}
-
-/* Assign selected pchans to the bone group that the user selects */
-static int pose_group_assign_exec(bContext *C, wmOperator *op)
-{
- Object *ob = ED_pose_object_from_context(C);
- bPose *pose;
- short done = FALSE;
-
- /* only continue if there's an object, and a pose there too */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- pose = ob->pose;
-
- /* set the active group number to the one from operator props
- * - if 0 after this, make a new group...
- */
- pose->active_group = RNA_int_get(op->ptr, "type");
- if (pose->active_group == 0)
- BKE_pose_add_group(ob);
-
- /* add selected bones to group then */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- pchan->agrp_index = pose->active_group;
- done = TRUE;
- }
- CTX_DATA_END;
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- /* report done status */
- if (done)
- return OPERATOR_FINISHED;
- else
- return OPERATOR_CANCELLED;
-}
-
-void POSE_OT_group_assign(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Add Selected to Bone Group";
- ot->idname = "POSE_OT_group_assign";
- ot->description = "Add selected bones to the chosen bone group";
-
- /* api callbacks */
- ot->invoke = pose_groups_menu_invoke;
- ot->exec = pose_group_assign_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_int(ot->srna, "type", 0, 0, INT_MAX, "Bone Group Index", "", 0, 10);
-}
-
-
-static int pose_group_unassign_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_pose_object_from_context(C);
- short done = FALSE;
-
- /* only continue if there's an object, and a pose there too */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- /* find selected bones to remove from all bone groups */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- if (pchan->agrp_index) {
- pchan->agrp_index = 0;
- done = TRUE;
- }
- }
- CTX_DATA_END;
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- /* report done status */
- if (done)
- return OPERATOR_FINISHED;
- else
- return OPERATOR_CANCELLED;
-}
-
-void POSE_OT_group_unassign(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Remove Selected from Bone Groups";
- ot->idname = "POSE_OT_group_unassign";
- ot->description = "Remove selected bones from all bone groups";
-
- /* api callbacks */
- ot->exec = pose_group_unassign_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int group_move_exec(bContext *C, wmOperator *op)
-{
- Object *ob = ED_pose_object_from_context(C);
- bPose *pose = (ob) ? ob->pose : NULL;
- bPoseChannel *pchan;
- bActionGroup *grp;
- int dir = RNA_enum_get(op->ptr, "direction");
- int grpIndexA, grpIndexB;
-
- if (ELEM(NULL, ob, pose))
- return OPERATOR_CANCELLED;
- if (pose->active_group <= 0)
- return OPERATOR_CANCELLED;
-
- /* get group to move */
- grp = BLI_findlink(&pose->agroups, pose->active_group - 1);
- if (grp == NULL)
- return OPERATOR_CANCELLED;
-
- /* move bone group */
- grpIndexA = pose->active_group;
- if (dir == 1) { /* up */
- void *prev = grp->prev;
-
- if (prev == NULL)
- return OPERATOR_FINISHED;
-
- BLI_remlink(&pose->agroups, grp);
- BLI_insertlinkbefore(&pose->agroups, prev, grp);
-
- grpIndexB = grpIndexA - 1;
- pose->active_group--;
- }
- else { /* down */
- void *next = grp->next;
-
- if (next == NULL)
- return OPERATOR_FINISHED;
-
- BLI_remlink(&pose->agroups, grp);
- BLI_insertlinkafter(&pose->agroups, next, grp);
-
- grpIndexB = grpIndexA + 1;
- pose->active_group++;
- }
-
- /* fix changed bone group indices in bones (swap grpIndexA with grpIndexB) */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->agrp_index == grpIndexB)
- pchan->agrp_index = grpIndexA;
- else if (pchan->agrp_index == grpIndexA)
- pchan->agrp_index = grpIndexB;
- }
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_group_move(wmOperatorType *ot)
-{
- static EnumPropertyItem group_slot_move[] = {
- {1, "UP", 0, "Up", ""},
- {-1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Move Bone Group";
- ot->idname = "POSE_OT_group_move";
- ot->description = "Change position of active Bone Group in list of Bone Groups";
-
- /* api callbacks */
- ot->exec = group_move_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_enum(ot->srna, "direction", group_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
-}
-
-/* bone group sort element */
-typedef struct tSortActionGroup {
- bActionGroup *agrp;
- int index;
-} tSortActionGroup;
-
-/* compare bone groups by name */
-static int compare_agroup(const void *sgrp_a_ptr, const void *sgrp_b_ptr)
-{
- tSortActionGroup *sgrp_a = (tSortActionGroup *)sgrp_a_ptr;
- tSortActionGroup *sgrp_b = (tSortActionGroup *)sgrp_b_ptr;
-
- return strcmp(sgrp_a->agrp->name, sgrp_b->agrp->name);
-}
-
-static int group_sort_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_pose_object_from_context(C);
- bPose *pose = (ob) ? ob->pose : NULL;
- bPoseChannel *pchan;
- tSortActionGroup *agrp_array;
- bActionGroup *agrp;
- int agrp_count;
- int i;
-
- if (ELEM(NULL, ob, pose))
- return OPERATOR_CANCELLED;
- if (pose->active_group <= 0)
- return OPERATOR_CANCELLED;
-
- /* create temporary array with bone groups and indices */
- agrp_count = BLI_countlist(&pose->agroups);
- agrp_array = MEM_mallocN(sizeof(tSortActionGroup) * agrp_count, "sort bone groups");
- for (agrp = pose->agroups.first, i = 0; agrp; agrp = agrp->next, i++) {
- BLI_assert(i < agrp_count);
- agrp_array[i].agrp = agrp;
- agrp_array[i].index = i + 1;
- }
-
- /* sort bone groups by name */
- qsort(agrp_array, agrp_count, sizeof(tSortActionGroup), compare_agroup);
-
- /* create sorted bone group list from sorted array */
- pose->agroups.first = pose->agroups.last = NULL;
- for (i = 0; i < agrp_count; i++) {
- BLI_addtail(&pose->agroups, agrp_array[i].agrp);
- }
-
- /* fix changed bone group indizes in bones */
- for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- for (i = 0; i < agrp_count; i++) {
- if (pchan->agrp_index == agrp_array[i].index) {
- pchan->agrp_index = i + 1;
- break;
- }
- }
- }
-
- /* free temp resources */
- MEM_freeN(agrp_array);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_group_sort(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Sort Bone Groups";
- ot->idname = "POSE_OT_group_sort";
- ot->description = "Sort Bone Groups by their names in ascending order";
-
- /* api callbacks */
- ot->exec = group_sort_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static void pose_group_select(bContext *C, Object *ob, int select)
-{
- bPose *pose = ob->pose;
-
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
- {
- if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
- if (select) {
- if (pchan->agrp_index == pose->active_group)
- pchan->bone->flag |= BONE_SELECTED;
- }
- else {
- if (pchan->agrp_index == pose->active_group)
- pchan->bone->flag &= ~BONE_SELECTED;
- }
- }
- }
- CTX_DATA_END;
-}
-
-static int pose_group_select_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_pose_object_from_context(C);
-
- /* only continue if there's an object, and a pose there too */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- pose_group_select(C, ob, 1);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_group_select(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Bones of Bone Group";
- ot->idname = "POSE_OT_group_select";
- ot->description = "Select bones in active Bone Group";
-
- /* api callbacks */
- ot->exec = pose_group_select_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int pose_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = ED_pose_object_from_context(C);
-
- /* only continue if there's an object, and a pose there too */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
-
- pose_group_select(C, ob, 0);
-
- /* notifiers for updates */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_group_deselect(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Deselect Bone Group";
- ot->idname = "POSE_OT_group_deselect";
- ot->description = "Deselect bones of active Bone Group";
-
- /* api callbacks */
- ot->exec = pose_group_deselect_exec;
- ot->poll = ED_operator_posemode_context;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ********************************************** */
-
-static int pose_flip_names_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm;
-
- /* paranoia checks */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
- arm = ob->data;
-
- /* loop through selected bones, auto-naming them */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- char newname[MAXBONENAME];
- flip_side_name(newname, pchan->name, TRUE);
- ED_armature_bone_rename(arm, pchan->name, newname);
- }
- CTX_DATA_END;
-
- /* since we renamed stuff... */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_flip_names(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Flip Names";
- ot->idname = "POSE_OT_flip_names";
- ot->description = "Flips (and corrects) the axis suffixes of the the names of selected bones";
-
- /* api callbacks */
- ot->exec = pose_flip_names_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ------------------ */
-
-static int pose_autoside_names_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm;
- char newname[MAXBONENAME];
- short axis = RNA_enum_get(op->ptr, "axis");
-
- /* paranoia checks */
- if (ELEM(NULL, ob, ob->pose))
- return OPERATOR_CANCELLED;
- arm = ob->data;
-
- /* loop through selected bones, auto-naming them */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- BLI_strncpy(newname, pchan->name, sizeof(newname));
- if (bone_autoside_name(newname, 1, axis, pchan->bone->head[axis], pchan->bone->tail[axis]))
- ED_armature_bone_rename(arm, pchan->name, newname);
- }
- CTX_DATA_END;
-
- /* since we renamed stuff... */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_autoside_names(wmOperatorType *ot)
-{
- static EnumPropertyItem axis_items[] = {
- {0, "XAXIS", 0, "X-Axis", "Left/Right"},
- {1, "YAXIS", 0, "Y-Axis", "Front/Back"},
- {2, "ZAXIS", 0, "Z-Axis", "Top/Bottom"},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "AutoName by Axis";
- ot->idname = "POSE_OT_autoside_names";
- ot->description = "Automatically renames the selected bones according to which side of the target axis they fall on";
-
- /* api callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = pose_autoside_names_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* settings */
- ot->prop = RNA_def_enum(ot->srna, "axis", axis_items, 0, "Axis", "Axis tag names with");
-}
-
-/* ********************************************** */
-
-static int pose_bone_rotmode_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_active_object(C);
- int mode = RNA_enum_get(op->ptr, "type");
-
- /* set rotation mode of selected bones */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- pchan->rotmode = mode;
- }
- CTX_DATA_END;
-
- /* notifiers and updates */
- DAG_id_tag_update((ID *)ob, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_rotation_mode_set(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Set Rotation Mode";
- ot->idname = "POSE_OT_rotation_mode_set";
- ot->description = "Set the rotation representation used by selected bones";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = pose_bone_rotmode_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", posebone_rotmode_items, 0, "Rotation Mode", "");
-}
-
-/* ********************************************** */
-
-/* Show all armature layers */
-static int pose_armature_layers_showall_poll(bContext *C)
-{
- /* this single operator can be used in posemode OR editmode for armatures */
- return ED_operator_posemode(C) || ED_operator_editarmature(C);
-}
-
-static int pose_armature_layers_showall_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (ob) ? ob->data : NULL;
- PointerRNA ptr;
- int maxLayers = (RNA_boolean_get(op->ptr, "all")) ? 32 : 16;
- int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
- int i;
-
- /* sanity checking */
- if (arm == NULL)
- return OPERATOR_CANCELLED;
-
- /* use RNA to set the layers
- * although it would be faster to just set directly using bitflags, we still
- * need to setup a RNA pointer so that we get the "update" callbacks for free...
- */
- RNA_id_pointer_create(&arm->id, &ptr);
-
- for (i = 0; i < maxLayers; i++)
- layers[i] = 1;
-
- RNA_boolean_set_array(&ptr, "layers", layers);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- /* done */
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_layers_show_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Show All Layers";
- ot->idname = "ARMATURE_OT_layers_show_all";
- ot->description = "Make all armature layers visible";
-
- /* callbacks */
- ot->exec = pose_armature_layers_showall_exec;
- ot->poll = pose_armature_layers_showall_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All Layers", "Enable all layers or just the first 16 (top row)");
-}
-
-/* ------------------- */
-
-/* Present a popup to get the layers that should be used */
-static int pose_armature_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bArmature *arm = (ob) ? ob->data : NULL;
- PointerRNA ptr;
- int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
-
- /* sanity checking */
- if (arm == NULL)
- return OPERATOR_CANCELLED;
-
- /* get RNA pointer to armature data to use that to retrieve the layers as ints to init the operator */
- RNA_id_pointer_create((ID *)arm, &ptr);
- RNA_boolean_get_array(&ptr, "layers", layers);
- RNA_boolean_set_array(op->ptr, "layers", layers);
-
- /* part to sync with other similar operators... */
- return WM_operator_props_popup(C, op, evt);
-}
-
-/* Set the visible layers for the active armature (edit and pose modes) */
-static int pose_armature_layers_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- PointerRNA ptr;
- int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
-
- if (ELEM(NULL, ob, ob->data)) {
- return OPERATOR_CANCELLED;
- }
-
- /* get the values set in the operator properties */
- RNA_boolean_get_array(op->ptr, "layers", layers);
-
- /* get pointer for armature, and write data there... */
- RNA_id_pointer_create((ID *)ob->data, &ptr);
- RNA_boolean_set_array(&ptr, "layers", layers);
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-
-void POSE_OT_armature_layers(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Change Armature Layers";
- ot->idname = "POSE_OT_armature_layers";
- ot->description = "Change the visible armature layers";
-
- /* callbacks */
- ot->invoke = pose_armature_layers_invoke;
- ot->exec = pose_armature_layers_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers to make visible");
-}
-
-void ARMATURE_OT_armature_layers(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Change Armature Layers";
- ot->idname = "ARMATURE_OT_armature_layers";
- ot->description = "Change the visible armature layers";
-
- /* callbacks */
- ot->invoke = pose_armature_layers_invoke;
- ot->exec = pose_armature_layers_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers to make visible");
-}
-
-/* ------------------- */
-
-/* Present a popup to get the layers that should be used */
-static int pose_bone_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt)
-{
- int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
-
- /* get layers that are active already */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- short bit;
-
- /* loop over the bits for this pchan's layers, adding layers where they're needed */
- for (bit = 0; bit < 32; bit++) {
- if (pchan->bone->layer & (1 << bit))
- layers[bit] = 1;
- }
- }
- CTX_DATA_END;
-
- /* copy layers to operator */
- RNA_boolean_set_array(op->ptr, "layers", layers);
-
- /* part to sync with other similar operators... */
- return WM_operator_props_popup(C, op, evt);
-}
-
-/* Set the visible layers for the active armature (edit and pose modes) */
-static int pose_bone_layers_exec(bContext *C, wmOperator *op)
-{
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- PointerRNA ptr;
- int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
-
- if (ob == NULL || ob->data == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- /* get the values set in the operator properties */
- RNA_boolean_get_array(op->ptr, "layers", layers);
-
- /* set layers of pchans based on the values set in the operator props */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- /* get pointer for pchan, and write flags this way */
- RNA_pointer_create((ID *)ob->data, &RNA_Bone, pchan->bone, &ptr);
- RNA_boolean_set_array(&ptr, "layers", layers);
- }
- CTX_DATA_END;
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_bone_layers(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Change Bone Layers";
- ot->idname = "POSE_OT_bone_layers";
- ot->description = "Change the layers that the selected bones belong to";
-
- /* callbacks */
- ot->invoke = pose_bone_layers_invoke;
- ot->exec = pose_bone_layers_exec;
- ot->poll = ED_operator_posemode_exclusive;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to");
-}
-
-/* ------------------- */
-
-/* Present a popup to get the layers that should be used */
-static int armature_bone_layers_invoke(bContext *C, wmOperator *op, wmEvent *evt)
-{
- int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
-
- /* get layers that are active already */
- CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones)
- {
- short bit;
-
- /* loop over the bits for this pchan's layers, adding layers where they're needed */
- for (bit = 0; bit < 32; bit++) {
- if (ebone->layer & (1 << bit))
- layers[bit] = 1;
- }
- }
- CTX_DATA_END;
-
- /* copy layers to operator */
- RNA_boolean_set_array(op->ptr, "layers", layers);
-
- /* part to sync with other similar operators... */
- return WM_operator_props_popup(C, op, evt);
-}
-
-/* Set the visible layers for the active armature (edit and pose modes) */
-static int armature_bone_layers_exec(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_edit_object(C);
- bArmature *arm = (ob) ? ob->data : NULL;
- PointerRNA ptr;
- int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
-
- /* get the values set in the operator properties */
- RNA_boolean_get_array(op->ptr, "layers", layers);
-
- /* set layers of pchans based on the values set in the operator props */
- CTX_DATA_BEGIN (C, EditBone *, ebone, selected_editable_bones)
- {
- /* get pointer for pchan, and write flags this way */
- RNA_pointer_create((ID *)arm, &RNA_EditBone, ebone, &ptr);
- RNA_boolean_set_array(&ptr, "layers", layers);
- }
- CTX_DATA_END;
-
- /* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_bone_layers(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Change Bone Layers";
- ot->idname = "ARMATURE_OT_bone_layers";
- ot->description = "Change the layers that the selected bones belong to";
-
- /* callbacks */
- ot->invoke = armature_bone_layers_invoke;
- ot->exec = armature_bone_layers_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean_layer_member(ot->srna, "layers", 32, NULL, "Layer", "Armature layers that bone belongs to");
-}
-
-/* ********************************************** */
-/* Flip Quats */
-
-static int pose_flip_quats_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
-
- /* loop through all selected pchans, flipping and keying (as needed) */
- CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
- {
- /* only if bone is using quaternion rotation */
- if (pchan->rotmode == ROT_MODE_QUAT) {
- /* quaternions have 720 degree range */
- negate_v4(pchan->quat);
-
- ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
- }
- }
- CTX_DATA_END;
-
- /* notifiers and updates */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_quaternions_flip(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Flip Quats";
- ot->idname = "POSE_OT_quaternions_flip";
- ot->description = "Flip quaternion values to achieve desired rotations, while maintaining the same orientations";
-
- /* callbacks */
- ot->exec = pose_flip_quats_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ********************************************** */
-/* Clear User Transforms */
-
-static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- float cframe = (float)CFRA;
- const short only_select = RNA_boolean_get(op->ptr, "only_selected");
-
- if ((ob->adt) && (ob->adt->action)) {
- /* XXX: this is just like this to avoid contaminating anything else;
- * just pose values should change, so this should be fine
- */
- bPose *dummyPose = NULL;
- Object workob = {{0}};
- bPoseChannel *pchan;
-
- /* execute animation step for current frame using a dummy copy of the pose */
- BKE_pose_copy_data(&dummyPose, ob->pose, 0);
-
- BLI_strncpy(workob.id.name, "OB<ClearTfmWorkOb>", sizeof(workob.id.name));
- workob.type = OB_ARMATURE;
- workob.data = ob->data;
- workob.adt = ob->adt;
- workob.pose = dummyPose;
-
- BKE_animsys_evaluate_animdata(scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM);
-
- /* copy back values, but on selected bones only */
- for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
- pose_bone_do_paste(ob, pchan, only_select, 0);
- }
-
- /* free temp data - free manually as was copied without constraints */
- for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->prop) {
- IDP_FreeProperty(pchan->prop);
- MEM_freeN(pchan->prop);
- }
- }
-
- /* was copied without constraints */
- BLI_freelistN(&dummyPose->chanbase);
- MEM_freeN(dummyPose);
- }
- else {
- /* no animation, so just reset whole pose to rest pose
- * (cannot just restore for selected though)
- */
- BKE_pose_rest(ob->pose);
- }
-
- /* notifiers and updates */
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
-
- return OPERATOR_FINISHED;
-}
-
-void POSE_OT_user_transforms_clear(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Clear User Transforms";
- ot->idname = "POSE_OT_user_transforms_clear";
- ot->description = "Reset pose on selected bones to keyframed state";
-
- /* callbacks */
- ot->exec = pose_clear_user_transforms_exec;
- ot->poll = ED_operator_posemode;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "only_selected", TRUE, "Only Selected", "Only visible/selected bones");
-}
-
diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c
index 1b5c550df11..454b0f0bceb 100644
--- a/source/blender/editors/armature/reeb.c
+++ b/source/blender/editors/armature/reeb.c
@@ -24,29 +24,14 @@
* \ingroup edarmature
*/
-#include <math.h>
-#include <string.h> /* for memcpy */
-#include <stdio.h>
-#include <stdlib.h> /* for qsort */
-#include <float.h>
-
-#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
-
#include "MEM_guardedalloc.h"
#include "BKE_context.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
-#include "BLI_utildefines.h"
#include "BLI_edgehash.h"
#include "BLI_ghash.h"
-#include "BLI_heap.h"
-
-#include "BKE_mesh.h"
-
-#include "ONL_opennl.h"
#include "reeb.h"
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index 25df17d232a..c38ded49830 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -20,6 +20,7 @@
set(INC
../include
+ ../../blenfont
../../blenkernel
../../blenlib
../../blenloader
@@ -42,4 +43,8 @@ set(SRC
curve_intern.h
)
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
blender_add_lib(bf_editor_curve "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/curve/SConscript b/source/blender/editors/curve/SConscript
index abefd3c6dd6..21c6a3732fa 100644
--- a/source/blender/editors/curve/SConscript
+++ b/source/blender/editors/curve/SConscript
@@ -29,9 +29,14 @@ Import ('env')
sources = env.Glob('*.c')
-incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
+defs = []
+
+incs = '../include ../../blenfont ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../bmesh ../../gpu ../../blenloader'
incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern'
-env.BlenderLib ( 'bf_editors_curve', sources, Split(incs), [], libtype=['core'], priority=[45] )
+if env['WITH_BF_INTERNATIONAL']:
+ defs.append('WITH_INTERNATIONAL')
+
+env.BlenderLib ( 'bf_editors_curve', sources, Split(incs), defs, libtype=['core'], priority=[45] )
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index b5aa55dbda9..d01e5c5d9bf 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -53,6 +53,8 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#include "BLF_translation.h"
+
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_depsgraph.h"
@@ -4925,7 +4927,7 @@ static int toggle_cyclic_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(eve
for (nu = editnurb->first; nu; nu = nu->next) {
if (nu->pntsu > 1 || nu->pntsv > 1) {
if (nu->type == CU_NURBS) {
- pup = uiPupMenuBegin(C, "Direction", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Direction"), ICON_NONE);
layout = uiPupMenuLayout(pup);
uiItemsEnumO(layout, op->type->idname, "direction");
uiPupMenuEnd(C, pup);
@@ -6051,14 +6053,14 @@ static int delete_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
uiLayout *layout;
if (obedit->type == OB_SURF) {
- pup = uiPupMenuBegin(C, "Delete", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Delete"), ICON_NONE);
layout = uiPupMenuLayout(pup);
uiItemEnumO_ptr(layout, op->type, NULL, 0, "type", 0);
uiItemEnumO_ptr(layout, op->type, NULL, 0, "type", 2);
uiPupMenuEnd(C, pup);
}
else {
- pup = uiPupMenuBegin(C, "Delete", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Delete"), ICON_NONE);
layout = uiPupMenuLayout(pup);
uiItemsEnumO(layout, op->type->idname, "type");
uiPupMenuEnd(C, pup);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 8cd2bd861bc..46815450bf2 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -931,7 +931,8 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
/* 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))) {
+ ((!ELEM(V2D_IS_CLIPPED, x1, y1)) && BLI_rcti_isect_pt(rect, x1, y1)))
+ {
/* 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
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 4db79df033e..30ac360cab6 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -137,7 +137,7 @@ struct EditBone *ED_armature_edit_bone_add(struct bArmature *arm, const char *na
void ED_armature_edit_bone_remove(struct bArmature *arm, EditBone *exBone);
void transform_armature_mirror_update(struct Object *obedit);
-void docenter_armature(struct Scene *scene, struct Object *ob, float cursor[3], int centermode, int around);
+void ED_armature_origin_set(struct Scene *scene, struct Object *ob, float cursor[3], int centermode, int around);
void ED_armature_apply_transform(struct Object *ob, float mat[4][4]);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 46f4515e0ca..d89d66dd62c 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -105,9 +105,10 @@ void ED_view3d_depth_tag_update(struct RegionView3D *rv3d);
typedef enum {
V3D_PROJ_RET_OK = 0,
V3D_PROJ_RET_CLIP_NEAR = 1, /* can't avoid this when in perspective mode, (can't avoid) */
- V3D_PROJ_RET_CLIP_BB = 2, /* bounding box clip - RV3D_CLIPPING */
- V3D_PROJ_RET_CLIP_WIN = 3, /* outside window bounds */
- V3D_PROJ_RET_OVERFLOW = 4 /* outside range (mainly for short), (can't avoid) */
+ V3D_PROJ_RET_CLIP_ZERO = 2, /* so close to zero we can't apply a perspective matrix usefully */
+ V3D_PROJ_RET_CLIP_BB = 3, /* bounding box clip - RV3D_CLIPPING */
+ V3D_PROJ_RET_CLIP_WIN = 4, /* outside window bounds */
+ V3D_PROJ_RET_OVERFLOW = 5 /* outside range (mainly for short), (can't avoid) */
} eV3DProjStatus;
/* some clipping tests are optional */
@@ -116,10 +117,13 @@ typedef enum {
V3D_PROJ_TEST_CLIP_BB = (1 << 0),
V3D_PROJ_TEST_CLIP_WIN = (1 << 1),
V3D_PROJ_TEST_CLIP_NEAR = (1 << 2),
+ V3D_PROJ_TEST_CLIP_ZERO = (1 << 3)
} eV3DProjTest;
-#define V3D_PROJ_TEST_CLIP_DEFAULT (V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR)
-#define V3D_PROJ_TEST_ALL (V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR)
+#define V3D_PROJ_TEST_CLIP_DEFAULT \
+ (V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR)
+#define V3D_PROJ_TEST_ALL \
+ (V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR | V3D_PROJ_TEST_CLIP_ZERO)
/* view3d_iterators.c */
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 78689c078c6..3c8a9a87fbe 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -183,6 +183,7 @@ typedef struct uiLayout uiLayout;
/* scale fixed button widths by this to account for DPI */
#define UI_DPI_FAC ((U.pixelsize * (float)U.dpi) / 72.0f)
+#define UI_DPI_WINDOW_FAC (((float)U.dpi) / 72.0f)
/* 16 to copy ICON_DEFAULT_HEIGHT */
#define UI_DPI_ICON_SIZE ((float)16 * UI_DPI_FAC)
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 37249896e34..2c17a629ed4 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -1097,34 +1097,29 @@ void uiDrawBlock(const bContext *C, uiBlock *block)
/* ************* EVENTS ************* */
-static void ui_is_but_sel(uiBut *but, double *value)
+int ui_is_but_push_ex(uiBut *but, double *value)
{
- short is_push = 0; /* (0 == UNSELECT), (1 == SELECT), (2 == DO-NOHING) */
- short is_true = TRUE;
-
- if (ELEM3(but->type, TOGN, ICONTOGN, OPTIONN)) {
- is_true = FALSE;
- }
+ int is_push = false; /* (0 == UNSELECT), (1 == SELECT), (-1 == DO-NOHING) */
if (but->bit) {
+ const bool state = ELEM3(but->type, TOGN, ICONTOGN, OPTIONN) ? false : true;
int lvalue;
UI_GET_BUT_VALUE_INIT(but, *value);
lvalue = (int)*value;
if (UI_BITBUT_TEST(lvalue, (but->bitnr))) {
- is_push = is_true;
+ is_push = state;
}
else {
- is_push = !is_true;
+ is_push = !state;
}
}
else {
switch (but->type) {
case BUT:
- is_push = 2;
- break;
case HOTKEYEVT:
case KEYEVT:
- is_push = 2;
+ case COLOR:
+ is_push = -1;
break;
case TOGBUT:
case TOG:
@@ -1134,42 +1129,48 @@ static void ui_is_but_sel(uiBut *but, double *value)
case ICONTOG:
case OPTION:
UI_GET_BUT_VALUE_INIT(but, *value);
- if (*value != (double)but->hardmin) is_push = 1;
+ if (*value != (double)but->hardmin) is_push = true;
break;
case ICONTOGN:
case TOGN:
case OPTIONN:
UI_GET_BUT_VALUE_INIT(but, *value);
- if (*value == 0.0) is_push = 1;
+ if (*value == 0.0) is_push = true;
break;
case ROW:
case LISTROW:
UI_GET_BUT_VALUE_INIT(but, *value);
/* support for rna enum buts */
if (but->rnaprop && (RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG)) {
- if ((int)*value & (int)but->hardmax) is_push = 1;
+ if ((int)*value & (int)but->hardmax) is_push = true;
}
else {
- if (*value == (double)but->hardmax) is_push = 1;
+ if (*value == (double)but->hardmax) is_push = true;
}
break;
- case COLOR:
- is_push = 2;
- break;
default:
- is_push = 2;
+ is_push = -1;
break;
}
}
-
- if (is_push == 2) {
- /* pass */
- }
- else if (is_push == 1) {
- but->flag |= UI_SELECT;
- }
- else {
- but->flag &= ~UI_SELECT;
+
+ return is_push;
+}
+int ui_is_but_push(uiBut *but)
+{
+ double value = UI_BUT_VALUE_UNSET;
+ return ui_is_but_push_ex(but, &value);
+}
+
+static void ui_check_but_select(uiBut *but, double *value)
+{
+ switch (ui_is_but_push_ex(but, value)) {
+ case true:
+ but->flag |= UI_SELECT;
+ break;
+ case false:
+ but->flag &= ~UI_SELECT;
+ break;
}
}
@@ -1620,8 +1621,7 @@ void ui_set_but_val(uiBut *but, double value)
value = *((float *)but->poin) = (float)value;
}
- /* update select flag */
- ui_is_but_sel(but, &value);
+ ui_check_but_select(but, &value);
}
int ui_get_but_string_max_length(uiBut *but)
@@ -2256,7 +2256,7 @@ void ui_check_but(uiBut *but)
double value = UI_BUT_VALUE_UNSET;
// float okwidth; // UNUSED
- ui_is_but_sel(but, &value);
+ ui_check_but_select(but, &value);
/* only update soft range while not editing */
if (but->rnaprop && !(but->editval || but->editstr || but->editvec)) {
@@ -3929,15 +3929,20 @@ void uiButGetStrInfo(bContext *C, uiBut *but, ...)
}
}
else if (type == BUT_GET_RNA_LABEL_CONTEXT) {
+ const char *_tmp = NULL;
if (but->rnaprop)
- tmp = BLI_strdup(RNA_property_translation_context(but->rnaprop));
+ _tmp = RNA_property_translation_context(but->rnaprop);
else if (but->optype)
- tmp = BLI_strdup(RNA_struct_translation_context(but->optype->srna));
+ _tmp = RNA_struct_translation_context(but->optype->srna);
else if (ELEM(but->type, MENU, PULLDOWN)) {
MenuType *mt = uiButGetMenuType(but);
if (mt)
- tmp = BLI_strdup(RNA_struct_translation_context(mt->ext.srna));
+ _tmp = RNA_struct_translation_context(mt->ext.srna);
+ }
+ if (!_tmp) { /* _tmp == BLF_I18NCONTEXT_DEFAULT */
+ _tmp = BLF_I18NCONTEXT_DEFAULT_BPY;
}
+ tmp = BLI_strdup(_tmp);
}
else if (ELEM3(type, BUT_GET_RNAENUM_IDENTIFIER, BUT_GET_RNAENUM_LABEL, BUT_GET_RNAENUM_TIP)) {
PointerRNA *ptr = NULL;
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 5cff61f4239..e0d6c293be5 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -81,6 +81,8 @@
/* place the mouse at the scaled down location when un-grabbing */
#define USE_CONT_MOUSE_CORRECT
+/* support dragging toggle buttons */
+#define USE_DRAG_TOGGLE
/* proto */
static void ui_add_smart_controller(bContext *C, uiBut *from, uiBut *to);
@@ -151,6 +153,7 @@ typedef struct uiHandleButtonData {
int maxlen, selextend, selstartx;
/* number editing / dragging */
+ /* coords are Window/uiBlock relative (depends on the button) */
int draglastx, draglasty;
int dragstartx, dragstarty;
int dragchange, draglock, dragsel;
@@ -406,9 +409,9 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
}
}
-static void ui_apply_autokey_undo(bContext *C, uiBut *but)
+/* typically call ui_apply_undo(), ui_apply_autokey() */
+static void ui_apply_undo(uiBut *but)
{
- Scene *scene = CTX_data_scene(C);
uiAfterFunc *after;
if (but->flag & UI_BUT_UNDO) {
@@ -430,6 +433,11 @@ static void ui_apply_autokey_undo(bContext *C, uiBut *but)
BLI_strncpy(after->undostr, str, sizeof(after->undostr));
BLI_addtail(&UIAfterFuncs, after);
}
+}
+
+static void ui_apply_autokey(bContext *C, uiBut *but)
+{
+ Scene *scene = CTX_data_scene(C);
/* try autokey */
ui_but_anim_autokey(C, but, scene, scene->r.cfra);
@@ -732,6 +740,153 @@ static void ui_apply_but_CHARTAB(bContext *C, uiBut *but, uiHandleButtonData *da
/* ****************** drag drop code *********************** */
+#ifdef USE_DRAG_TOGGLE
+
+typedef struct uiDragToggleHandle {
+ /* init */
+ bool is_set;
+ float but_cent_start[2];
+ eButType but_type_start;
+
+ bool xy_lock[2];
+ int xy_last[2];
+} uiDragToggleHandle;
+
+static bool ui_drag_toggle_set_xy_xy(bContext *C, ARegion *ar, const bool is_set, const eButType but_type_start,
+ const int xy_src[2], const int xy_dst[2])
+{
+ bool change = false;
+ uiBlock *block;
+
+ for (block = ar->uiblocks.first; block; block = block->next) {
+ uiBut *but;
+
+ float xy_a_block[2] = {UNPACK2(xy_src)};
+ float xy_b_block[2] = {UNPACK2(xy_dst)};
+
+ ui_window_to_block_fl(ar, block, &xy_a_block[0], &xy_a_block[1]);
+ ui_window_to_block_fl(ar, block, &xy_b_block[0], &xy_b_block[1]);
+
+ for (but = block->buttons.first; but; but = but->next) {
+ if (ui_is_but_interactive(but)) {
+ if (BLI_rctf_isect_segment(&but->rect, xy_a_block, xy_b_block)) {
+
+ /* execute the button */
+ if (ui_is_but_bool(but) && but->type == but_type_start) {
+ /* is it pressed? */
+ bool is_set_but = ui_is_but_push(but);
+ BLI_assert(ui_is_but_bool(but) == true);
+ if (is_set_but != is_set) {
+ uiButExecute(C, but);
+ change = true;
+ }
+ }
+ /* done */
+
+ }
+ }
+ }
+ }
+
+ return change;
+}
+
+static void ui_drag_toggle_set(bContext *C, uiDragToggleHandle *drag_info, const int xy_input[2])
+{
+ ARegion *ar = CTX_wm_region(C);
+ bool do_draw = false;
+ int xy[2];
+
+ /**
+ * Initialize Locking:
+ *
+ * Check if we need to initialize the lock axis by finding if the first
+ * button we mouse over is X or Y aligned, then lock the mouse to that axis after.
+ */
+ if (drag_info->xy_lock[0] == false && drag_info->xy_lock[1] == false) {
+ ARegion *ar = CTX_wm_region(C);
+
+ /* first store the buttons original coords */
+ uiBut *but = ui_but_find_mouse_over(ar, xy_input[0], xy_input[1]);
+ if (but) {
+ const float but_cent_new[2] = {BLI_rctf_cent_x(&but->rect),
+ BLI_rctf_cent_y(&but->rect)};
+
+ /* check if this is a different button, chances are high the button wont move about :) */
+ if (len_manhattan_v2v2(drag_info->but_cent_start, but_cent_new) > 1.0f) {
+ if (fabsf(drag_info->but_cent_start[0] - but_cent_new[0]) <
+ fabsf(drag_info->but_cent_start[1] - but_cent_new[1]))
+ {
+ drag_info->xy_lock[0] = true;
+ }
+ else {
+ drag_info->xy_lock[1] = true;
+ }
+ }
+ }
+ }
+ /* done with axis locking */
+
+
+ xy[0] = (drag_info->xy_lock[0] == false) ? xy_input[0] : drag_info->xy_last[0];
+ xy[1] = (drag_info->xy_lock[1] == false) ? xy_input[1] : drag_info->xy_last[1];
+
+
+ /* touch all buttons between last mouse coord and this one */
+ do_draw = ui_drag_toggle_set_xy_xy(C, ar, drag_info->is_set, drag_info->but_type_start, drag_info->xy_last, xy);
+
+ if (do_draw) {
+ ED_region_tag_redraw(ar);
+ }
+
+ copy_v2_v2_int(drag_info->xy_last, xy);
+}
+
+static void ui_handler_region_drag_toggle_remove(bContext *UNUSED(C), void *userdata)
+{
+ uiDragToggleHandle *drag_info = userdata;
+ MEM_freeN(drag_info);
+}
+
+static int ui_handler_region_drag_toggle(bContext *C, const wmEvent *event, void *userdata)
+{
+ uiDragToggleHandle *drag_info = userdata;
+ bool done = false;
+
+ switch (event->type) {
+ case LEFTMOUSE:
+ {
+ if (event->val != KM_PRESS) {
+ done = true;
+ }
+ break;
+ }
+ case MOUSEMOVE:
+ {
+ ui_drag_toggle_set(C, drag_info, &event->x);
+ break;
+ }
+ }
+
+ if (done) {
+ wmWindow *win = CTX_wm_window(C);
+ WM_event_remove_ui_handler(&win->modalhandlers,
+ ui_handler_region_drag_toggle,
+ ui_handler_region_drag_toggle_remove,
+ drag_info, false);
+ ui_handler_region_drag_toggle_remove(C, drag_info);
+
+ WM_event_add_mousemove(C);
+ return WM_UI_HANDLER_BREAK;
+ }
+ else {
+ return WM_UI_HANDLER_CONTINUE;
+ }
+}
+
+#endif /* USE_DRAG_TOGGLE */
+
+
static int ui_but_mouse_inside_icon(uiBut *but, ARegion *ar, const wmEvent *event)
{
rcti rect;
@@ -765,18 +920,24 @@ static int ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data,
button_activate_state(C, but, BUTTON_STATE_EXIT);
data->cancel = TRUE;
-
+#ifdef USE_DRAG_TOGGLE
if (ui_is_but_bool(but)) {
- const bool is_set = (ui_get_but_val(but) != 0.0);
- PointerRNA ptr;
- WM_operator_properties_create(&ptr, "UI_OT_drag_toggle");
- RNA_boolean_set(&ptr, "state", !is_set);
- RNA_int_set(&ptr, "last_x", data->dragstartx);
- RNA_int_set(&ptr, "last_y", data->dragstarty);
- WM_operator_name_call(C, "UI_OT_drag_toggle", WM_OP_INVOKE_DEFAULT, &ptr);
- WM_operator_properties_free(&ptr);
+ uiDragToggleHandle *drag_info = MEM_callocN(sizeof(*drag_info), __func__);
+
+ drag_info->is_set = ui_is_but_push(but);
+ drag_info->but_cent_start[0] = BLI_rctf_cent_x(&but->rect);
+ drag_info->but_cent_start[1] = BLI_rctf_cent_y(&but->rect);
+ drag_info->but_type_start = but->type;
+ copy_v2_v2_int(drag_info->xy_last, &event->x);
+
+ WM_event_add_ui_handler(C, &data->window->modalhandlers,
+ ui_handler_region_drag_toggle,
+ ui_handler_region_drag_toggle_remove,
+ drag_info);
}
- else {
+ else
+#endif
+ {
wmDrag *drag;
drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but));
@@ -2485,25 +2646,32 @@ static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHa
static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
+#ifdef USE_DRAG_TOGGLE
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (event->type == LEFTMOUSE && event->val == KM_PRESS && ui_is_but_bool(but)) {
+ data->togdual = event->ctrl;
+ data->togonly = !event->shift;
+ ui_apply_button(C, but->block, but, data, true);
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->x;
data->dragstarty = event->y;
- return WM_UI_HANDLER_CONTINUE;
+ return WM_UI_HANDLER_BREAK;
}
-
+ }
+ else if (data->state == BUTTON_STATE_WAIT_DRAG) {
+ /* note: the 'BUTTON_STATE_WAIT_DRAG' part of 'ui_do_but_EXIT' could be refactored into its own function */
+ data->applied = false;
+ return ui_do_but_EXIT(C, but, data, event);
+ }
+#endif
+ if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
data->togdual = event->ctrl;
data->togonly = !event->shift;
button_activate_state(C, but, BUTTON_STATE_EXIT);
- return WM_UI_HANDLER_CONTINUE;
+ return WM_UI_HANDLER_BREAK;
}
}
- else if (data->state == BUTTON_STATE_WAIT_DRAG) {
- /* note: the 'BUTTON_STATE_WAIT_DRAG' part of 'ui_do_but_EXIT' could be refactored into its own function */
- return ui_do_but_EXIT(C, but, data, event);
- }
return WM_UI_HANDLER_CONTINUE;
}
@@ -2524,13 +2692,15 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
return WM_UI_HANDLER_CONTINUE;
}
}
+#ifdef USE_DRAG_TOGGLE
if (event->type == LEFTMOUSE && ui_is_but_bool(but)) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->x;
data->dragstarty = event->y;
return WM_UI_HANDLER_CONTINUE;
}
-
+#endif
+
if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
int ret = WM_UI_HANDLER_BREAK;
/* XXX (a bit ugly) Special case handling for filebrowser drag button */
@@ -3246,13 +3416,14 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
return WM_UI_HANDLER_BREAK;
}
}
+#ifdef USE_DRAG_TOGGLE
if (event->type == LEFTMOUSE && ui_is_but_bool(but)) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->x;
data->dragstarty = event->y;
return WM_UI_HANDLER_BREAK;
}
-
+#endif
/* regular open menu */
if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
@@ -4253,7 +4424,7 @@ static int ui_numedit_but_HISTOGRAM(uiBut *but, uiHandleButtonData *data, int mx
if (in_scope_resize_zone(but, data->dragstartx, data->dragstarty)) {
/* resize histogram widget itself */
- hist->height = (BLI_rctf_size_y(&but->rect) + (data->dragstarty - my))/UI_DPI_FAC;
+ hist->height = (BLI_rctf_size_y(&but->rect) + (data->dragstarty - my)) / UI_DPI_FAC;
}
else {
/* scale histogram values (dy / 10 for better control) */
@@ -4337,7 +4508,7 @@ static int ui_numedit_but_WAVEFORM(uiBut *but, uiHandleButtonData *data, int mx,
if (in_scope_resize_zone(but, data->dragstartx, data->dragstarty)) {
/* resize waveform widget itself */
- scopes->wavefrm_height = (BLI_rctf_size_y(&but->rect) + (data->dragstarty - my))/UI_DPI_FAC;
+ scopes->wavefrm_height = (BLI_rctf_size_y(&but->rect) + (data->dragstarty - my)) / UI_DPI_FAC;
}
else {
/* scale waveform values */
@@ -4419,7 +4590,7 @@ static int ui_numedit_but_VECTORSCOPE(uiBut *but, uiHandleButtonData *data, int
if (in_scope_resize_zone(but, data->dragstartx, data->dragstarty)) {
/* resize vectorscope widget itself */
- scopes->vecscope_height = (BLI_rctf_size_y(&but->rect) + (data->dragstarty - my))/UI_DPI_FAC;
+ scopes->vecscope_height = (BLI_rctf_size_y(&but->rect) + (data->dragstarty - my)) / UI_DPI_FAC;
}
data->draglastx = mx;
@@ -4622,7 +4793,7 @@ static int ui_numedit_but_TRACKPREVIEW(bContext *C, uiBut *but, uiHandleButtonDa
if (in_scope_resize_zone(but, data->dragstartx, data->dragstarty)) {
/* resize preview widget itself */
- scopes->track_preview_height = (BLI_rctf_size_y(&but->rect) + (data->dragstarty - my))/UI_DPI_FAC;
+ scopes->track_preview_height = (BLI_rctf_size_y(&but->rect) + (data->dragstarty - my)) / UI_DPI_FAC;
}
else {
if (!scopes->track_locked) {
@@ -5452,6 +5623,24 @@ static int ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y)
return 1;
}
+/**
+ * Can we mouse over the button or is it hidden/disabled/layout.
+ */
+bool ui_is_but_interactive(uiBut *but)
+{
+ /* note, LABEL is included for highlights, this allows drags */
+ if (but->type == LABEL && but->dragpoin == NULL)
+ return false;
+ if (ELEM3(but->type, ROUNDBOX, SEPR, LISTBOX))
+ return false;
+ if (but->flag & UI_HIDDEN)
+ return false;
+ if (but->flag & UI_SCROLLED)
+ return false;
+
+ return true;
+}
+
uiBut *ui_but_find_mouse_over(ARegion *ar, int x, int y)
{
uiBlock *block;
@@ -5469,17 +5658,11 @@ uiBut *ui_but_find_mouse_over(ARegion *ar, int x, int y)
ui_window_to_block(ar, block, &mx, &my);
for (but = block->buttons.first; but; but = but->next) {
- /* note, LABEL is included for highlights, this allows drags */
- if (but->type == LABEL && but->dragpoin == NULL)
- continue;
- if (ELEM3(but->type, ROUNDBOX, SEPR, LISTBOX))
- continue;
- if (but->flag & UI_HIDDEN)
- continue;
- if (but->flag & UI_SCROLLED)
- continue;
- if (ui_but_contains_pt(but, mx, my))
- butover = but;
+ if (ui_is_but_interactive(but)) {
+ if (ui_but_contains_pt(but, mx, my)) {
+ butover = but;
+ }
+ }
}
/* CLIP_EVENTS prevents the event from reaching other blocks */
@@ -5795,7 +5978,8 @@ static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *da
if (!onfree && !data->cancel) {
/* autokey & undo push */
- ui_apply_autokey_undo(C, but);
+ ui_apply_undo(but);
+ ui_apply_autokey(C, but);
/* popup menu memory */
if (block->flag & UI_BLOCK_POPUP_MEMORY)
@@ -5820,12 +6004,13 @@ static void button_activate_exit(bContext *C, uiBut *but, uiHandleButtonData *da
/* redraw (data is but->active!) */
ED_region_tag_redraw(data->region);
-
+
/* clean up button */
if (but->active) {
MEM_freeN(but->active);
but->active = NULL;
}
+
but->flag &= ~(UI_ACTIVE | UI_SELECT);
but->flag |= UI_BUT_LAST_ACTIVE;
if (!onfree)
@@ -6084,6 +6269,7 @@ void ui_button_execute_do(struct bContext *C, struct ARegion *ar, uiBut *but)
data->region = ar;
ui_apply_button(C, but->block, but, data, true);
/* use onfree event so undo is handled by caller and apply is already done above */
+ ui_apply_autokey(C, but);
button_activate_exit((bContext *)C, but, data, false, true);
but->active = active_back;
}
@@ -6107,14 +6293,12 @@ static void ui_handle_button_activate(bContext *C, ARegion *ar, uiBut *but, uiBu
static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
{
- uiHandleButtonData *data;
+ uiHandleButtonData *data = but->active;
+ const uiButtonActivateType state_orig = data->state;
uiBlock *block;
ARegion *ar;
- uiBut *postbut;
- uiButtonActivateType posttype;
int retval;
- data = but->active;
block = but->block;
ar = data->region;
@@ -6266,14 +6450,28 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
}
if (data->state == BUTTON_STATE_EXIT) {
- postbut = data->postbut;
- posttype = data->posttype;
+ uiBut *post_but = data->postbut;
+ uiButtonActivateType post_type = data->posttype;
- button_activate_exit(C, but, data, (postbut == NULL), false);
+ button_activate_exit(C, but, data, (post_but == NULL), false);
/* for jumping to the next button with tab while text editing */
- if (postbut)
- button_activate_init(C, ar, postbut, posttype);
+ if (post_but) {
+ button_activate_init(C, ar, post_but, post_type);
+ }
+ else {
+ /* XXX issue is because WM_event_add_mousemove(C) is a bad hack and not reliable,
+ *if that gets coded better this bypass can go away too.
+ *
+ * This is needed to make sure if a button was active,
+ * it stays active while the mouse is over it.
+ * This avoids adding mousemoves, see: [#33466] */
+ if (ELEM(state_orig, BUTTON_ACTIVATE, BUTTON_ACTIVATE_OVER)) {
+ if (ui_but_find_mouse_over(ar, event->x, event->y) == but) {
+ button_activate_init(C, ar, but, state_orig);
+ }
+ }
+ }
}
return retval;
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index f0e59f1f935..9093e8f8d30 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -171,8 +171,8 @@ struct uiBut {
char *str;
char strdata[UI_MAX_NAME_STR];
char drawstr[UI_MAX_DRAW_STR];
-
- rctf rect;
+
+ rctf rect; /* block relative coords */
char *poin;
float hardmin, hardmax, softmin, softmax;
@@ -225,7 +225,7 @@ struct uiBut {
void *rename_orig;
uiLink *link;
- short linkto[2];
+ short linkto[2]; /* region relative coords */
const char *tip, *lockstr;
@@ -410,6 +410,11 @@ extern int ui_is_but_bool(uiBut *but);
extern int ui_is_but_unit(uiBut *but);
extern int ui_is_but_rna_valid(uiBut *but);
extern int ui_is_but_utf8(uiBut *but);
+extern bool ui_is_but_interactive(uiBut *but);
+
+extern int ui_is_but_push_ex(uiBut *but, double *value);
+extern int ui_is_but_push(uiBut *but);
+
extern void ui_bounds_block(uiBlock *block);
extern void ui_block_translate(uiBlock *block, int x, int y);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index c69f53a53d2..1e95b4df762 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -2263,6 +2263,7 @@ uiLayout *uiLayoutRow(uiLayout *layout, int align)
litem->enabled = 1;
litem->context = layout->context;
litem->space = (align) ? 0 : layout->root->style->buttonspacex;
+ litem->redalert = layout->redalert;
litem->w = layout->w;
BLI_addtail(&layout->items, litem);
@@ -2283,6 +2284,7 @@ uiLayout *uiLayoutColumn(uiLayout *layout, int align)
litem->enabled = 1;
litem->context = layout->context;
litem->space = (litem->align) ? 0 : layout->root->style->buttonspacey;
+ litem->redalert = layout->redalert;
litem->w = layout->w;
BLI_addtail(&layout->items, litem);
@@ -2303,6 +2305,7 @@ uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align)
flow->litem.enabled = 1;
flow->litem.context = layout->context;
flow->litem.space = (flow->litem.align) ? 0 : layout->root->style->columnspace;
+ flow->litem.redalert = layout->redalert;
flow->litem.w = layout->w;
flow->number = number;
BLI_addtail(&layout->items, flow);
@@ -2323,6 +2326,7 @@ static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type)
box->litem.enabled = 1;
box->litem.context = layout->context;
box->litem.space = layout->root->style->columnspace;
+ box->litem.redalert = layout->redalert;
box->litem.w = layout->w;
BLI_addtail(&layout->items, box);
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index d48d699d881..3298859ee0c 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1071,222 +1071,6 @@ static void UI_OT_reloadtranslation(wmOperatorType *ot)
ot->exec = reloadtranslation_exec;
}
-
-/* -------------------------------------------------------------------- */
-/* Toggle Drag Operator */
-
-typedef struct DragOpInfo {
- bool xy_lock[2];
- float but_cent_start[2];
- eButType but_type_start;
-} DragOpInfo;
-
-typedef struct DragOpPlotData {
- bContext *C;
- ARegion *ar;
- bool is_set;
- eButType but_type_start;
- bool do_draw;
- const uiBut *but_prev;
-} DragOpPlotData;
-
-static const uiBut *ui_but_set_xy(bContext *C, ARegion *ar, const bool is_set, const eButType but_type_start,
- const int xy[2], const uiBut *but_prev)
-{
- uiBut *but = ui_but_find_mouse_over(ar, xy[0], xy[1]);
-
- if (but_prev == but) {
- return but_prev;
- }
-
- if (but && ui_is_but_bool(but) && but->type == but_type_start) {
- /* is it pressed? */
- bool is_set_but = (ui_get_but_val(but) != 0.0);
- BLI_assert(ui_is_but_bool(but) == true);
- if (is_set_but != is_set) {
- uiButExecute(C, but);
- return but;
- }
- }
-
- return but_prev;
-}
-
-static int ui_but_set_cb(int x, int y, void *data_v)
-{
- DragOpPlotData *data = data_v;
- int xy[2] = {x, y};
- data->but_prev = ui_but_set_xy(data->C, data->ar, data->is_set, data->but_type_start, xy, data->but_prev);
- return 1; /* keep going */
-}
-
-/* operates on buttons between 2 mouse-points */
-static bool ui_but_set_xy_xy(bContext *C, ARegion *ar, const bool is_set, const eButType but_type_start,
- const int xy_src[2], const int xy_dst[2])
-{
- DragOpPlotData data;
- data.C = C;
- data.ar = ar;
- data.is_set = is_set;
- data.but_type_start = but_type_start;
- data.do_draw = false;
- data.but_prev = NULL;
-
-
- /* prevent dragging too fast loosing buttons */
- plot_line_v2v2i(xy_src, xy_dst, ui_but_set_cb, &data);
-
- return data.do_draw;
-}
-
-static void ui_drag_but_set(bContext *C, wmOperator *op, const int xy_input[2])
-{
- ARegion *ar = CTX_wm_region(C);
- DragOpInfo *drag_info = op->customdata;
- bool do_draw = false;
-
- const bool is_set = RNA_boolean_get(op->ptr, "state");
- const int xy_last[2] = {RNA_int_get(op->ptr, "last_x"),
- RNA_int_get(op->ptr, "last_y")};
-
- int xy[2];
-
- /**
- * Initialize Locking:
- *
- * Check if we need to initialize the lock axis by finding if the first
- * button we mouse over is X or Y aligned, then lock the mouse to that axis after.
- */
- if (drag_info->xy_lock[0] == false && drag_info->xy_lock[1] == false) {
- ARegion *ar = CTX_wm_region(C);
-
- /* first store the buttons original coords */
- uiBut *but = ui_but_find_mouse_over(ar, xy_input[0], xy_input[1]);
- if (but) {
- const float but_cent_new[2] = {BLI_rctf_cent_x(&but->rect),
- BLI_rctf_cent_y(&but->rect)};
-
- /* check if this is a different button, chances are high the button wont move about :) */
- if (len_manhattan_v2v2(drag_info->but_cent_start, but_cent_new) > 1.0f) {
- if (fabsf(drag_info->but_cent_start[0] - but_cent_new[0]) <
- fabsf(drag_info->but_cent_start[1] - but_cent_new[1]))
- {
- drag_info->xy_lock[0] = true;
- }
- else {
- drag_info->xy_lock[1] = true;
- }
- }
- }
- }
- /* done with axis locking */
-
-
- xy[0] = (drag_info->xy_lock[0] == false) ? xy_input[0] : xy_last[0];
- xy[1] = (drag_info->xy_lock[1] == false) ? xy_input[1] : xy_last[1];
-
-
- /* touch all buttons between last mouse coord and this one */
- do_draw = ui_but_set_xy_xy(C, ar, is_set, drag_info->but_type_start, xy_last, xy);
-
- if (do_draw) {
- ED_region_tag_redraw(ar);
- }
-
- RNA_int_set(op->ptr, "last_x", xy[0]);
- RNA_int_set(op->ptr, "last_y", xy[1]);
-}
-
-static int ui_drag_toggle_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
- int xy_last[2] = {RNA_int_get(op->ptr, "last_x"),
- RNA_int_get(op->ptr, "last_y")};
-
- float but_cent_start[2];
- eButType but_type_start;
- DragOpInfo *drag_info;
-
- {
- /* find the button where we started dragging */
- ARegion *ar = CTX_wm_region(C);
- uiBut *but = ui_but_find_mouse_over(ar, xy_last[0], xy_last[1]);
- if (but) {
- but_cent_start[0] = BLI_rctf_cent_x(&but->rect);
- but_cent_start[1] = BLI_rctf_cent_y(&but->rect);
- but_type_start = but->type;
- }
- else {
- return OPERATOR_CANCELLED;
- }
- }
-
- drag_info = op->customdata = MEM_callocN(sizeof(DragOpInfo), __func__);
- copy_v2_v2(drag_info->but_cent_start, but_cent_start);
- drag_info->but_type_start = but_type_start;
-
- /* set the initial button */
- ui_drag_but_set(C, op, xy_last);
- ui_drag_but_set(C, op, &event->x);
-
- WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int ui_drag_toggle_modal(bContext *C, wmOperator *op, wmEvent *event)
-{
- bool done = false;
-
- switch (event->type) {
- case LEFTMOUSE:
- {
- if (event->val != KM_PRESS) {
- done = true;
- }
- break;
- }
- case MOUSEMOVE:
- {
- ui_drag_but_set(C, op, &event->x);
- break;
- }
- }
-
- if (done) {
- MEM_freeN(op->customdata);
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_RUNNING_MODAL;
- }
-}
-
-static int ui_drag_toggle_cancel(bContext *UNUSED(C), wmOperator *op)
-{
- MEM_freeN(op->customdata);
- return OPERATOR_CANCELLED;
-}
-
-static void UI_OT_drag_toggle(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Button Drag Toggle";
- ot->description = "";
- ot->idname = "UI_OT_drag_toggle";
-
- /* api callbacks */
- ot->invoke = ui_drag_toggle_invoke;
- ot->modal = ui_drag_toggle_modal;
- ot->cancel = ui_drag_toggle_cancel;
-
- /* flags */
- ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
-
- /* properties */
- RNA_def_boolean(ot->srna, "state", true, "State", "");
- RNA_def_int(ot->srna, "last_x", 0, 0, INT_MAX, "X", "", 0, INT_MAX);
- RNA_def_int(ot->srna, "last_y", 0, 0, INT_MAX, "Y", "", 0, INT_MAX);
-}
-
/* ********************************************************* */
/* Registration */
@@ -1304,6 +1088,4 @@ void UI_buttons_operatortypes(void)
WM_operatortype_append(UI_OT_edittranslation_init);
#endif
WM_operatortype_append(UI_OT_reloadtranslation);
- WM_operatortype_append(UI_OT_drag_toggle);
}
-
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 900ba7de559..83540cef9fc 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -2594,7 +2594,8 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
/* if list length changes and active is out of view, scroll to it */
if ((ui_list->list_last_len != len) &&
- (activei < ui_list->list_scroll || activei >= ui_list->list_scroll + items)) {
+ (activei < ui_list->list_scroll || activei >= ui_list->list_scroll + items))
+ {
ui_list->list_scroll = activei;
}
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 68df8e29957..dd7b1d0ee06 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1855,7 +1855,7 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r
widget_verts_to_quad_strip(&wtb, totvert, quad_strip);
glVertexPointer(2, GL_FLOAT, 0, quad_strip);
- glDrawArrays(GL_QUAD_STRIP, 0, totvert * 2 + 2);
+ glDrawArrays(GL_QUAD_STRIP, 0, totvert * 2); /* add + 2 for getting a complete soft rect. Now it skips top edge to allow transparent menus */
}
glDisableClientState(GL_VERTEX_ARRAY);
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 7f1140501b5..daa78957231 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -1034,10 +1034,11 @@ static int view_zoomdrag_modal(bContext *C, wmOperator *op, wmEvent *event)
}
else {
/* 'continuous' or 'dolly' */
- float fac, zoomfac = 0.001f * v2d->maxzoom;
+ float fac, zoomfac = 0.01f;
/* some view2d's (graph) don't have min/max zoom, or extreme ones */
- CLAMP (zoomfac, 0.001f, 0.01f);
+ if (v2d->maxzoom > 0.0f)
+ zoomfac = CLAMPIS(0.001f * v2d->maxzoom, 0.001f, 0.01f);
/* x-axis transform */
fac = zoomfac * (event->x - vzd->lastx);
@@ -1116,7 +1117,7 @@ static void VIEW2D_OT_zoom(wmOperatorType *ot)
ot->poll = view_zoom_poll;
/* operator is repeatable */
- // ot->flag = OPTYPE_BLOCKING;
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
/* rna - must keep these in sync with the other operators */
RNA_def_float(ot->srna, "deltax", 0, -FLT_MAX, FLT_MAX, "Delta X", "", -FLT_MAX, FLT_MAX);
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index 7db23041c88..d4ae5b8b29b 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -47,4 +47,8 @@ if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
blender_add_lib(bf_editor_io "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/io/SConscript b/source/blender/editors/io/SConscript
index cef73f33ddd..b7449ccad79 100644
--- a/source/blender/editors/io/SConscript
+++ b/source/blender/editors/io/SConscript
@@ -36,4 +36,7 @@ incs += '../../makesdna ../../makesrna ../../windowmanager ../../collada'
if env['WITH_BF_COLLADA']:
defs += ['WITH_COLLADA']
+if env['WITH_BF_INTERNATIONAL']:
+ defs += ['WITH_INTERNATIONAL']
+
env.BlenderLib ( 'bf_editor_io', sources, Split(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 7703a8638c9..4908c101a7c 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -92,6 +92,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int use_texture_copies;
int active_uv_only;
+ int triangulate;
int use_object_instantiation;
int sort_by_name;
int second_life;
@@ -118,6 +119,7 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
use_texture_copies = RNA_boolean_get(op->ptr, "use_texture_copies");
active_uv_only = RNA_boolean_get(op->ptr, "active_uv_only");
+ triangulate = RNA_boolean_get(op->ptr, "triangulate");
use_object_instantiation = RNA_boolean_get(op->ptr, "use_object_instantiation");
sort_by_name = RNA_boolean_get(op->ptr, "sort_by_name");
second_life = RNA_boolean_get(op->ptr, "second_life");
@@ -140,9 +142,11 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
include_material_textures,
use_texture_copies,
+ triangulate,
use_object_instantiation,
sort_by_name,
- second_life)) {
+ second_life))
+ {
return OPERATOR_FINISHED;
}
else {
@@ -217,6 +221,8 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
uiItemL(row, IFACE_("Collada Options:"), ICON_MODIFIER);
row = uiLayoutRow(box, FALSE);
+ uiItemR(row, imfptr, "triangulate", 0, NULL, ICON_NONE);
+ row = uiLayoutRow(box, FALSE);
uiItemR(row, imfptr, "use_object_instantiation", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, FALSE);
uiItemR(row, imfptr, "sort_by_name", 0, NULL, ICON_NONE);
@@ -293,6 +299,9 @@ void WM_OT_collada_export(wmOperatorType *ot)
"Copy textures to same folder where the .dae file is exported");
+ RNA_def_boolean(ot->srna, "triangulate", 1, "Triangulate",
+ "Export Polygons (Quads & NGons) as Triangles");
+
RNA_def_boolean(ot->srna, "use_object_instantiation", 1, "Use Object Instances",
"Instantiate multiple Objects from same Data");
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 7ac27e038a4..7ddf2b54a88 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -181,11 +181,17 @@ void paintface_reveal(Object *ob)
static void hash_add_face(EdgeHash *ehash, MPoly *mp, MLoop *mloop)
{
- MLoop *ml;
- int i;
+ MLoop *ml, *ml_next;
+ int i = mp->totloop;
+
+ ml_next = mloop; /* first loop */
+ ml = &ml_next[i - 1]; /* last loop */
+
+ while (i-- != 0) {
+ BLI_edgehash_insert(ehash, ml->v, ml_next->v, NULL);
- for (i = 0, ml = mloop; i < mp->totloop; i++, ml++) {
- BLI_edgehash_insert(ehash, ml->v, ME_POLY_LOOP_NEXT(mloop, mp, i)->v, NULL);
+ ml = ml_next;
+ ml_next++;
}
}
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 57f116693f8..51161970c0b 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -933,9 +933,13 @@ static int edbm_select_mode_exec(bContext *C, wmOperator *op)
static int edbm_select_mode_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
- // RNA_enum_set(op->ptr, "type"); /* type must be set already */
- RNA_boolean_set(op->ptr, "use_extend", event->shift);
- RNA_boolean_set(op->ptr, "use_expand", event->ctrl);
+ /* detecting these options based on shift/ctrl here is weak, but it's done
+ * to make this work when clicking buttons or menus */
+ if (!RNA_struct_property_is_set(op->ptr, "use_extend"))
+ RNA_boolean_set(op->ptr, "use_extend", event->shift);
+ if (!RNA_struct_property_is_set(op->ptr, "use_expand"))
+ RNA_boolean_set(op->ptr, "use_expand", event->ctrl);
+
return edbm_select_mode_exec(C, op);
}
@@ -1358,6 +1362,22 @@ static int edgetag_context_check(Scene *scene, BMesh *bm, BMEdge *e)
return 0;
}
+static void edgetag_ensure_cd_flag(Scene *scene, Mesh *me)
+{
+ BMesh *bm = me->edit_btmesh->bm;
+
+ switch (scene->toolsettings->edge_mode) {
+ case EDGE_MODE_TAG_CREASE:
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
+ break;
+ case EDGE_MODE_TAG_BEVEL:
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT);
+ break;
+ default:
+ break;
+ }
+}
+
static int edgetag_shortest_path(Scene *scene, BMesh *bm, BMEdge *e_src, BMEdge *e_dst)
{
/* BM_ELEM_TAG flag is used to store visited edges */
@@ -1371,16 +1391,7 @@ static int edgetag_shortest_path(Scene *scene, BMesh *bm, BMEdge *e_src, BMEdge
/* note, would pass BM_EDGE except we are looping over all edges anyway */
BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */);
- switch (scene->toolsettings->edge_mode) {
- case EDGE_MODE_TAG_CREASE:
- BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(OBACT), ME_CDFLAG_EDGE_CREASE);
- break;
- case EDGE_MODE_TAG_BEVEL:
- BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(OBACT), ME_CDFLAG_EDGE_BWEIGHT);
- break;
- default:
- break;
- }
+ edgetag_ensure_cd_flag(scene, OBACT->data);
BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) {
if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == FALSE) {
@@ -1470,7 +1481,7 @@ static int mouse_mesh_shortest_path_edge(ViewContext *vc)
e_dst = EDBM_edge_find_nearest(vc, &dist);
if (e_dst) {
Mesh *me = vc->obedit->data;
- int path = 0;
+ bool is_path = false;
if (em->bm->selected.last) {
BMEditSelection *ese = em->bm->selected.last;
@@ -1481,13 +1492,14 @@ static int mouse_mesh_shortest_path_edge(ViewContext *vc)
if (e_act != e_dst) {
if (edgetag_shortest_path(vc->scene, em->bm, e_act, e_dst)) {
BM_select_history_remove(em->bm, e_act);
- path = 1;
+ is_path = true;
}
}
}
}
- if (path == 0) {
+ if (is_path == false) {
int act = (edgetag_context_check(vc->scene, em->bm, e_dst) == 0);
+ edgetag_ensure_cd_flag(vc->scene, vc->obedit->data);
edgetag_context_set(em->bm, vc->scene, e_dst, act); /* switch the edge option */
}
@@ -2963,7 +2975,7 @@ void MESH_OT_select_random(wmOperatorType *ot)
/* 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);
- RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
static int edbm_select_next_loop_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index dcb25423b80..92e1dbf433f 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -3321,7 +3321,8 @@ static int edbm_fill_exec(bContext *C, wmOperator *op)
if (!EDBM_op_init(em, &bmop, op,
"triangle_fill edges=%he use_beauty=%b",
- BM_ELEM_SELECT, use_beauty)) {
+ BM_ELEM_SELECT, use_beauty))
+ {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index f983a43f573..378f6374336 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -149,7 +149,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* remove tessface to ensure we don't old references to invalid faces */
+ /* remove tessface to ensure we don't hold references to invalid faces */
BKE_mesh_tessface_clear(me);
/* new material indices and material array */
@@ -309,6 +309,10 @@ int join_mesh_exec(bContext *C, wmOperator *op)
me = base->object->data;
if (me->totvert) {
+
+ /* merge customdata flag */
+ ((Mesh *)ob->data)->cd_flag |= me->cd_flag;
+
/* standard data */
CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
CustomData_copy_data(&me->vdata, &vdata, 0, vertofs, me->totvert);
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index bc577f6ee29..997cbb71683 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -67,6 +67,7 @@
#include "BKE_displist.h"
#include "BKE_effect.h"
#include "BKE_group.h"
+#include "BKE_image.h"
#include "BKE_lamp.h"
#include "BKE_lattice.h"
#include "BKE_library.h"
@@ -735,6 +736,83 @@ void OBJECT_OT_empty_add(wmOperatorType *ot)
ED_object_add_generic_props(ot, FALSE);
}
+static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ Base *base = NULL;
+ Image *ima = NULL;
+ Object *ob = NULL;
+
+ /* check image input variables */
+ if (RNA_struct_property_is_set(op->ptr, "filepath")) {
+ char path[FILE_MAX];
+
+ RNA_string_get(op->ptr, "filepath", path);
+ ima = BKE_image_load_exists(path);
+ }
+ else if (RNA_struct_property_is_set(op->ptr, "name")) {
+ char name[MAX_ID_NAME - 2];
+
+ RNA_string_get(op->ptr, "name", name);
+ ima = (Image *)BKE_libblock_find_name(ID_IM, name);
+ }
+
+ if (ima == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Not an image");
+ return OPERATOR_CANCELLED;
+ }
+
+ base = ED_view3d_give_base_under_cursor(C, event->mval);
+
+ /* if empty under cursor, then set object */
+ if (base && base->object->type == OB_EMPTY) {
+ ob = base->object;
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, CTX_data_scene(C));
+ }
+ else {
+ /* add new empty */
+ unsigned int layer;
+ float rot[3];
+
+ if (!ED_object_add_generic_get_opts(C, op, NULL, rot, NULL, &layer, NULL))
+ return OPERATOR_CANCELLED;
+
+ ob = ED_object_add_type(C, OB_EMPTY, NULL, rot, FALSE, layer);
+
+ /* add under the mouse */
+ ED_object_location_from_view(C, ob->loc);
+ ED_view3d_cursor3d_position(C, ob->loc, event->mval);
+ }
+
+ ob->empty_drawtype = OB_EMPTY_IMAGE;
+ ob->data = ima;
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_drop_named_image(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Add Empty Image/Drop Image To Empty";
+ ot->description = "Add an empty image type to scene with data";
+ ot->idname = "OBJECT_OT_drop_named_image";
+
+ /* api callbacks */
+ ot->invoke = empty_drop_named_image_invoke;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_string(ot->srna, "filepath", "", FILE_MAX, "Filepath", "Path to image file");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_string(ot->srna, "name", "", MAX_ID_NAME - 2, "Name", "Image name to assign");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ ED_object_add_generic_props(ot, FALSE);
+}
+
/********************* Add Lamp Operator ********************/
static const char *get_lamp_defname(int type)
@@ -2034,12 +2112,17 @@ static int add_named_exec(bContext *C, wmOperator *op)
}
basen->lay = basen->object->lay = scene->lay;
+ basen->object->restrictflag &= ~OB_RESTRICT_VIEW;
if (event) {
+ ARegion *ar = CTX_wm_region(C);
+ const int mval[2] = {event->x - ar->winrct.xmin,
+ event->y - ar->winrct.ymin};
ED_object_location_from_view(C, basen->object->loc);
- ED_view3d_cursor3d_position(C, basen->object->loc, event->mval);
+ ED_view3d_cursor3d_position(C, basen->object->loc, mval);
}
+ ED_base_object_select(basen, BA_SELECT);
ED_base_object_activate(C, basen);
copy_object_set_idnew(C, dupflag);
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 84b989e2f59..1bed7d7dd11 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -40,6 +40,8 @@
#include "BLI_dynstr.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "DNA_anim_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
@@ -1873,7 +1875,7 @@ static int pose_ik_add_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
}
/* prepare popup menu to choose targetting options */
- pup = uiPupMenuBegin(C, "Add IK", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Add IK"), ICON_NONE);
layout = uiPupMenuLayout(pup);
/* the type of targets we'll set determines the menu entries to show... */
@@ -1882,14 +1884,14 @@ static int pose_ik_add_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(evt))
* - the only thing that matters is that we want a target...
*/
if (tar_pchan)
- uiItemBooleanO(layout, "To Active Bone", ICON_NONE, "POSE_OT_ik_add", "with_targets", 1);
+ uiItemBooleanO(layout, IFACE_("To Active Bone"), ICON_NONE, "POSE_OT_ik_add", "with_targets", 1);
else
- uiItemBooleanO(layout, "To Active Object", ICON_NONE, "POSE_OT_ik_add", "with_targets", 1);
+ uiItemBooleanO(layout, IFACE_("To Active Object"), ICON_NONE, "POSE_OT_ik_add", "with_targets", 1);
}
else {
/* we have a choice of adding to a new empty, or not setting any target (targetless IK) */
- uiItemBooleanO(layout, "To New Empty Object", ICON_NONE, "POSE_OT_ik_add", "with_targets", 1);
- uiItemBooleanO(layout, "Without Targets", ICON_NONE, "POSE_OT_ik_add", "with_targets", 0);
+ uiItemBooleanO(layout, IFACE_("To New Empty Object"), ICON_NONE, "POSE_OT_ik_add", "with_targets", 1);
+ uiItemBooleanO(layout, IFACE_("Without Targets"), ICON_NONE, "POSE_OT_ik_add", "with_targets", 0);
}
/* finish building the menu, and process it (should result in calling self again) */
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 4523ac098d6..a302aa65fd0 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -113,6 +113,7 @@ void OBJECT_OT_metaball_add(struct wmOperatorType *ot);
void OBJECT_OT_text_add(struct wmOperatorType *ot);
void OBJECT_OT_armature_add(struct wmOperatorType *ot);
void OBJECT_OT_empty_add(struct wmOperatorType *ot);
+void OBJECT_OT_drop_named_image(struct wmOperatorType *ot);
void OBJECT_OT_lamp_add(struct wmOperatorType *ot);
void OBJECT_OT_effector_add(struct wmOperatorType *ot);
void OBJECT_OT_camera_add(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index bf408d6dbe4..e5aaaffade8 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -114,6 +114,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_text_add);
WM_operatortype_append(OBJECT_OT_armature_add);
WM_operatortype_append(OBJECT_OT_empty_add);
+ WM_operatortype_append(OBJECT_OT_drop_named_image);
WM_operatortype_append(OBJECT_OT_lamp_add);
WM_operatortype_append(OBJECT_OT_camera_add);
WM_operatortype_append(OBJECT_OT_speaker_add);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index c5e8310e9fb..f9dde043607 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -304,7 +304,7 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, wmEvent *evt)
}
else if (ob->id.lib) {
- uiPopupMenu *pup = uiPupMenuBegin(C, "OK?", ICON_QUESTION);
+ uiPopupMenu *pup = uiPupMenuBegin(C, IFACE_("OK?"), ICON_QUESTION);
uiLayout *layout = uiPupMenuLayout(pup);
/* create operator menu item with relevant properties filled in */
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index 775a2897513..baa0199baf7 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -50,6 +50,8 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "BKE_context.h"
#include "BKE_group.h"
#include "BKE_main.h"
@@ -606,7 +608,7 @@ static short select_grouped_group(bContext *C, Object *ob) /* Select objects in
}
/* build the menu. */
- pup = uiPupMenuBegin(C, "Select Group", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Select Group"), ICON_NONE);
layout = uiPupMenuLayout(pup);
for (i = 0; i < group_count; i++) {
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 01dcac2d1b4..3fa6c301fcb 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -871,7 +871,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
/* Function to recenter armatures in editarmature.c
* Bone + object locations are handled there.
*/
- docenter_armature(scene, ob, cursor, centermode, around);
+ ED_armature_origin_set(scene, ob, cursor, centermode, around);
tot_change++;
arm->id.flag |= LIB_DOIT;
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 87ff42ef4db..ef882b2486b 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -558,8 +558,10 @@ static int ed_vgroup_transfer_weight(Object *ob_dst, Object *ob_src, bDeformGrou
}
/* Loop through the vertices.*/
- for (i = 0, dv_src = dv_array_src, dv_dst = dv_array_dst; i < me_dst->totvert;
- i++, dv_dst++, dv_src++, mv_src++, mv_dst++) {
+ for (i = 0, dv_src = dv_array_src, dv_dst = dv_array_dst;
+ i < me_dst->totvert;
+ i++, dv_dst++, dv_src++, mv_src++, mv_dst++)
+ {
if (*dv_dst == NULL) {
continue;
@@ -2598,7 +2600,7 @@ static int vertex_group_poll(bContext *C)
return (ob && !ob->id.lib && OB_TYPE_SUPPORT_VGROUP(ob->type) && data && !data->lib);
}
-static int UNUSED_FUNCTION(vertex_group_poll_edit) (bContext * C)
+static int UNUSED_FUNCTION(vertex_group_poll_edit) (bContext *C)
{
Object *ob = ED_object_context(C);
ID *data = (ob) ? ob->data : NULL;
diff --git a/source/blender/editors/physics/physics_pointcache.c b/source/blender/editors/physics/physics_pointcache.c
index bbce94b6215..b9742c9968f 100644
--- a/source/blender/editors/physics/physics_pointcache.c
+++ b/source/blender/editors/physics/physics_pointcache.c
@@ -90,6 +90,20 @@ static void bake_console_progress_end(void *UNUSED(arg))
printf("\rbake: done!\n");
}
+static void ptcache_free_bake(PointCache *cache)
+{
+ if (cache->edit) {
+ if (!cache->edit->edited || 1) {// XXX okee("Lose changes done in particle mode?")) {
+ PE_free_ptcache_edit(cache->edit);
+ cache->edit = NULL;
+ cache->flag &= ~PTCACHE_BAKED;
+ }
+ }
+ else {
+ cache->flag &= ~PTCACHE_BAKED;
+ }
+}
+
static int ptcache_bake_all_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -139,7 +153,7 @@ static int ptcache_free_bake_all_exec(bContext *C, wmOperator *UNUSED(op))
BKE_ptcache_ids_from_object(&pidlist, base->object, scene, MAX_DUPLI_RECUR);
for (pid=pidlist.first; pid; pid=pid->next) {
- pid->cache->flag &= ~PTCACHE_BAKED;
+ ptcache_free_bake(pid->cache);
}
BLI_freelistN(&pidlist);
@@ -241,15 +255,7 @@ static int ptcache_free_bake_exec(bContext *C, wmOperator *UNUSED(op))
PointCache *cache= ptr.data;
Object *ob= ptr.id.data;
- if (cache->edit) {
- if (!cache->edit->edited || 1) {// XXX okee("Lose changes done in particle mode?")) {
- PE_free_ptcache_edit(cache->edit);
- cache->edit = NULL;
- cache->flag &= ~PTCACHE_BAKED;
- }
- }
- else
- cache->flag &= ~PTCACHE_BAKED;
+ ptcache_free_bake(cache);
WM_event_add_notifier(C, NC_OBJECT|ND_POINTCACHE, ob);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 46f726e45c6..1b7cd4a6d20 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1586,14 +1586,14 @@ int ED_area_header_standardbuttons(const bContext *C, uiBlock *block, int yco)
ICON_DISCLOSURE_TRI_RIGHT,
xco, yco, U.widget_unit, U.widget_unit * 0.9f,
&(sa->flag), 0, 0, 0, 0,
- "Show pulldown menus");
+ TIP_("Show pulldown menus"));
}
else {
but = uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, 0,
ICON_DISCLOSURE_TRI_DOWN,
xco, yco, U.widget_unit, U.widget_unit * 0.9f,
&(sa->flag), 0, 0, 0, 0,
- "Hide pulldown menus");
+ TIP_("Hide pulldown menus"));
}
uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */
@@ -1967,11 +1967,11 @@ void ED_region_visible_rect(ARegion *ar, rcti *rect)
if (BLI_rcti_isect(rect, &arn->winrct, NULL)) {
/* overlap left, also check 1 pixel offset (2 regions on one side) */
- if ( ABS(rect->xmin - arn->winrct.xmin) < 2)
+ if (ABS(rect->xmin - arn->winrct.xmin) < 2)
rect->xmin = arn->winrct.xmax;
/* overlap right */
- if ( ABS(rect->xmax - arn->winrct.xmax) < 2)
+ if (ABS(rect->xmax - arn->winrct.xmax) < 2)
rect->xmax = arn->winrct.xmin;
}
}
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 12a7a33c893..fcd0968d52f 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -206,7 +206,7 @@ int ED_operator_animview_active(bContext *C)
return TRUE;
}
- CTX_wm_operator_poll_msg_set(C, "expected an timeline/animation area to be active");
+ CTX_wm_operator_poll_msg_set(C, "expected a timeline/animation area to be active");
return 0;
}
@@ -3427,8 +3427,8 @@ static int userpref_show_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *ev
rcti rect;
int sizex, sizey;
- sizex = 800;
- sizey = 480;
+ sizex = 800 * UI_DPI_WINDOW_FAC;
+ sizey = 480 * UI_DPI_WINDOW_FAC;
/* some magic to calculate postition */
/* pixelsize: mouse coords are in U.pixelsize units :/ */
@@ -3447,8 +3447,8 @@ static int userpref_show_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *ev
static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Show/Hide User Preferences";
- ot->description = "Show/hide user preferences";
+ ot->name = "Show User Preferences";
+ ot->description = "Show user preferences";
ot->idname = "SCREEN_OT_userpref_show";
/* api callbacks */
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 1f7fee313b3..9cde62e8302 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -449,13 +449,21 @@ static void screenshot_endjob(void *sjv)
static int screencast_exec(bContext *C, wmOperator *op)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
bScreen *screen = CTX_wm_screen(C);
- wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), screen, "Screencast", 0, WM_JOB_TYPE_SCREENCAST);
- ScreenshotJob *sj = MEM_callocN(sizeof(ScreenshotJob), "screenshot job");
+ wmJob *wm_job;
+ ScreenshotJob *sj;
+ /* if called again, stop the running job */
+ if (WM_jobs_test(wm, screen, WM_JOB_TYPE_SCREENCAST))
+ WM_jobs_stop(wm, screen, screenshot_startjob);
+
+ wm_job = WM_jobs_get(wm, win, screen, "Screencast", 0, WM_JOB_TYPE_SCREENCAST);
+ sj = MEM_callocN(sizeof(ScreenshotJob), "screenshot job");
+
/* setup sj */
if (RNA_boolean_get(op->ptr, "full")) {
- wmWindow *win = CTX_wm_window(C);
sj->x = 0;
sj->y = 0;
sj->dumpsx = WM_window_pixels_x(win);
@@ -470,7 +478,7 @@ static int screencast_exec(bContext *C, wmOperator *op)
}
sj->bmain = CTX_data_main(C);
sj->scene = CTX_data_scene(C);
- sj->wm = CTX_wm_manager(C);
+ sj->wm = wm;
BKE_reports_init(&sj->reports, RPT_PRINT);
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index faa9ce00da8..e7c3ddd071b 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -151,12 +151,10 @@ void BRUSH_OT_curve_preset(struct wmOperatorType *ot);
void PAINT_OT_face_select_linked(struct wmOperatorType *ot);
void PAINT_OT_face_select_linked_pick(struct wmOperatorType *ot);
void PAINT_OT_face_select_all(struct wmOperatorType *ot);
-void PAINT_OT_face_select_inverse(struct wmOperatorType *ot);
void PAINT_OT_face_select_hide(struct wmOperatorType *ot);
void PAINT_OT_face_select_reveal(struct wmOperatorType *ot);
void PAINT_OT_vert_select_all(struct wmOperatorType *ot);
-void PAINT_OT_vert_select_inverse(struct wmOperatorType *ot);
int vert_paint_poll(struct bContext *C);
int mask_paint_poll(struct bContext *C);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 3cf67667f39..dffb8c39bf2 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -127,13 +127,14 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
void PAINT_OT_mask_flood_fill(struct wmOperatorType *ot)
{
static EnumPropertyItem mode_items[] = {
- {PAINT_MASK_FLOOD_VALUE, "VALUE", 0, "Value", "Set mask to the level specified by the \"value\" property"},
+ {PAINT_MASK_FLOOD_VALUE, "VALUE", 0, "Value", "Set mask to the level specified by the 'value' property"},
{PAINT_MASK_INVERT, "INVERT", 0, "Invert", "Invert the mask"},
{0}};
/* identifiers */
ot->name = "Mask Flood Fill";
ot->idname = "PAINT_OT_mask_flood_fill";
+ ot->description = "Fill the whole mask with a given value, or invert its values";
/* api callbacks */
ot->exec = mask_flood_fill_exec;
@@ -143,5 +144,6 @@ void PAINT_OT_mask_flood_fill(struct wmOperatorType *ot)
/* rna */
RNA_def_enum(ot->srna, "mode", mode_items, PAINT_MASK_FLOOD_VALUE, "Mode", NULL);
- RNA_def_float(ot->srna, "value", 0, 0, 1, "Value", "Mask level to use when mode is \"Value\"; zero means no masking and one is fully masked", 0, 1);
+ RNA_def_float(ot->srna, "value", 0, 0, 1, "Value",
+ "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked", 0, 1);
}
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index ba33ad22f92..7385c2f0cf1 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -485,7 +485,6 @@ void ED_operatortypes_paint(void)
/* vertex selection */
WM_operatortype_append(PAINT_OT_vert_select_all);
- WM_operatortype_append(PAINT_OT_vert_select_inverse);
/* vertex */
WM_operatortype_append(PAINT_OT_vertex_paint_toggle);
@@ -496,7 +495,6 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_face_select_linked);
WM_operatortype_append(PAINT_OT_face_select_linked_pick);
WM_operatortype_append(PAINT_OT_face_select_all);
- WM_operatortype_append(PAINT_OT_face_select_inverse);
WM_operatortype_append(PAINT_OT_face_select_hide);
WM_operatortype_append(PAINT_OT_face_select_reveal);
@@ -748,7 +746,8 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
keymap = WM_keymap_find(keyconf, "Weight Paint Vertex Selection", 0, 0);
keymap->poll = vert_paint_poll;
WM_keymap_add_item(keymap, "PAINT_OT_vert_select_all", AKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "PAINT_OT_vert_select_inverse", IKEY, KM_PRESS, KM_CTRL, 0);
+ kmi = WM_keymap_add_item(keymap, "PAINT_OT_vert_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
WM_keymap_add_item(keymap, "VIEW3D_OT_select_border", BKEY, KM_PRESS, 0, 0);
kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "deselect", FALSE);
@@ -777,7 +776,8 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
keymap->poll = facemask_paint_poll;
WM_keymap_add_item(keymap, "PAINT_OT_face_select_all", AKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "PAINT_OT_face_select_inverse", IKEY, KM_PRESS, KM_CTRL, 0);
+ kmi = WM_keymap_add_item(keymap, "PAINT_OT_face_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
kmi = WM_keymap_add_item(keymap, "PAINT_OT_face_select_hide", HKEY, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "unselected", FALSE);
kmi = WM_keymap_add_item(keymap, "PAINT_OT_face_select_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 4f156276aac..dc3f310b405 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -448,7 +448,7 @@ static int face_select_all_exec(bContext *C, wmOperator *op)
void PAINT_OT_face_select_all(wmOperatorType *ot)
{
- ot->name = "Face Selection";
+ ot->name = "(De)select All";
ot->description = "Change selection for all faces";
ot->idname = "PAINT_OT_face_select_all";
@@ -472,7 +472,7 @@ static int vert_select_all_exec(bContext *C, wmOperator *op)
void PAINT_OT_vert_select_all(wmOperatorType *ot)
{
- ot->name = "Vertex Selection";
+ ot->name = "(De)select All";
ot->description = "Change selection for all vertices";
ot->idname = "PAINT_OT_vert_select_all";
@@ -484,46 +484,6 @@ void PAINT_OT_vert_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
-static int vert_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
- paintvert_deselect_all_visible(ob, SEL_INVERT, TRUE);
- ED_region_tag_redraw(CTX_wm_region(C));
- return OPERATOR_FINISHED;
-}
-
-void PAINT_OT_vert_select_inverse(wmOperatorType *ot)
-{
- ot->name = "Vertex Select Invert";
- ot->description = "Invert selection of vertices";
- ot->idname = "PAINT_OT_vert_select_inverse";
-
- ot->exec = vert_select_inverse_exec;
- ot->poll = vert_paint_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-static int face_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
- paintface_deselect_all_visible(ob, SEL_INVERT, TRUE);
- ED_region_tag_redraw(CTX_wm_region(C));
- return OPERATOR_FINISHED;
-}
-
-
-void PAINT_OT_face_select_inverse(wmOperatorType *ot)
-{
- ot->name = "Face Select Invert";
- ot->description = "Invert selection of faces";
- ot->idname = "PAINT_OT_face_select_inverse";
-
- ot->exec = face_select_inverse_exec;
- ot->poll = facemask_paint_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
static int face_select_hide_exec(bContext *C, wmOperator *op)
{
const int unselected = RNA_boolean_get(op->ptr, "unselected");
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 8ff2a68013c..0277e1e11dc 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -913,7 +913,8 @@ static float calc_vp_alpha_dl(VPaint *vp, ViewContext *vc,
BLI_INLINE float wval_blend(const float weight, const float paintval, const float alpha)
{
- return (paintval * alpha) + (weight * (1.0f - alpha));
+ const float talpha = min_ff(alpha, 1.0f); /* blending with values over 1 doesn't make sense */
+ return (paintval * talpha) + (weight * (1.0f - talpha));
}
BLI_INLINE float wval_add(const float weight, const float paintval, const float alpha)
{
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 342671698d2..90e7645032b 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -2281,7 +2281,7 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
sculpt_brush_test_init(ss, &test);
- if (ss->cache->original) {
+ if (ss->cache->original && unode->co) {
BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
@@ -3742,7 +3742,8 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
/* not supported yet for multires or dynamic topology */
if (!ss->multires && !ss->bm && !ss->layer_co &&
- (brush->flag & BRUSH_PERSISTENT)) {
+ (brush->flag & BRUSH_PERSISTENT))
+ {
if (!ss->layer_co)
ss->layer_co = MEM_mallocN(sizeof(float) * 3 * ss->totvert,
"sculpt mesh vertices copy");
@@ -4784,6 +4785,7 @@ static void SCULPT_OT_symmetrize(wmOperatorType *ot)
/* identifiers */
ot->name = "Symmetrize";
ot->idname = "SCULPT_OT_symmetrize";
+ ot->description = "Symmetrize the topology modifications";
/* api callbacks */
ot->exec = sculpt_symmetrize_exec;
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index c828e8c8651..406756f4197 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -567,6 +567,8 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node,
unode->totvert = totvert;
}
+ else
+ maxgrid = 0;
/* we will use this while sculpting, is mapalloc slow to access then? */
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index 935b15f3cd8..16d194d0929 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -37,6 +37,8 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "DNA_brush_types.h"
#include "DNA_ID.h"
#include "DNA_lamp_types.h"
@@ -397,7 +399,7 @@ void uiTemplateTextureUser(uiLayout *layout, bContext *C)
user = ct->user;
if (!user) {
- uiItemL(layout, "No textures in context.", ICON_NONE);
+ uiItemL(layout, IFACE_("No textures in context"), ICON_NONE);
return;
}
diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c
index b2d31ececa5..9409ce42d3a 100644
--- a/source/blender/editors/space_clip/clip_buttons.c
+++ b/source/blender/editors/space_clip/clip_buttons.c
@@ -407,7 +407,7 @@ void uiTemplateMarker(uiLayout *layout, PointerRNA *ptr, const char *propname, P
if (track->flag & TRACK_LOCKED) {
uiLayoutSetActive(layout, FALSE);
block = uiLayoutAbsoluteBlock(layout);
- uiDefBut(block, LABEL, 0, IFACE_("Track is locked"), 0, 0, UI_UNIT_X*15.0f, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, IFACE_("Track is locked"), 0, 0, UI_UNIT_X * 15.0f, UI_UNIT_Y, NULL, 0, 0, 0, 0, "");
return;
}
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 77ed197c1d7..ac7ebd9ddac 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -2892,7 +2892,7 @@ 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 *********************/
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 9349abb4d8b..79a578a86d1 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -1178,11 +1178,10 @@ static void file_expand_directory(bContext *C)
get_default_root(sfile->params->dir);
}
/* change "C:" --> "C:\", [#28102] */
- else if ( (isalpha(sfile->params->dir[0]) &&
- (sfile->params->dir[1] == ':')) &&
- (sfile->params->dir[2] == '\0')
-
- ) {
+ else if ((isalpha(sfile->params->dir[0]) &&
+ (sfile->params->dir[1] == ':')) &&
+ (sfile->params->dir[2] == '\0'))
+ {
sfile->params->dir[2] = '\\';
sfile->params->dir[3] = '\0';
}
diff --git a/source/blender/editors/space_file/fsmenu.h b/source/blender/editors/space_file/fsmenu.h
index 1b69eb09fce..eea7e0e3837 100644
--- a/source/blender/editors/space_file/fsmenu.h
+++ b/source/blender/editors/space_file/fsmenu.h
@@ -64,7 +64,7 @@ char *fsmenu_get_entry(struct FSMenu *fsmenu, FSMenuCategory category, int index
/** Inserts a new fsmenu entry with the given \a path.
* Duplicate entries are not added.
- * \param sorted Should entry be inserted in sorted order?
+ * \param flag Options for inserting the entry.
*/
void fsmenu_insert_entry(struct FSMenu *fsmenu, FSMenuCategory category, const char *path, const FSMenuInsert flag);
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index ab16a9d55e6..f1501857b13 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -461,6 +461,7 @@ static void graph_panel_driverVar__singleProp(uiLayout *layout, ID *id, DriverVa
/* Target ID */
row = uiLayoutRow(layout, FALSE);
+ uiLayoutSetRedAlert(row, ((dtar->flag & DTAR_FLAG_INVALID) && !dtar->id));
uiTemplateAnyID(row, &dtar_ptr, "id", "id_type", IFACE_("Prop:"));
/* Target Property */
@@ -470,8 +471,9 @@ static void graph_panel_driverVar__singleProp(uiLayout *layout, ID *id, DriverVa
/* get pointer for resolving the property selected */
RNA_id_pointer_create(dtar->id, &root_ptr);
- col = uiLayoutColumn(layout, TRUE);
/* rna path */
+ col = uiLayoutColumn(layout, TRUE);
+ uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID));
uiTemplatePathBuilder(col, &dtar_ptr, "data_path", &root_ptr, IFACE_("Path"));
}
}
@@ -492,21 +494,23 @@ 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:"));
-
+
if (dtar->id && 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);
}
col = uiLayoutColumn(layout, TRUE);
+ uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", IFACE_("Bone 2:"));
if (dtar2->id && 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);
}
@@ -515,7 +519,7 @@ static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *
/* settings for 'location difference' driver variable type */
static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *dvar)
{
- DriverTarget *dtar = &dvar->targets[0];
+ DriverTarget *dtar = &dvar->targets[0];
DriverTarget *dtar2 = &dvar->targets[1];
Object *ob1 = (Object *)dtar->id;
Object *ob2 = (Object *)dtar2->id;
@@ -523,32 +527,36 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *
uiLayout *col;
/* initialize RNA pointer to the target */
- RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
+ RNA_pointer_create(id, &RNA_DriverTarget, dtar, &dtar_ptr);
RNA_pointer_create(id, &RNA_DriverTarget, dtar2, &dtar2_ptr);
/* 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:"));
if (dtar->id && 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);
}
-
+
+ uiLayoutSetRedAlert(col, false); /* we can clear it again now - it's only needed when creating the ID/Bone fields */
uiItemR(col, &dtar_ptr, "transform_space", 0, NULL, ICON_NONE);
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:"));
if (dtar2->id && 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);
}
+ uiLayoutSetRedAlert(col, false); /* we can clear it again now - it's only needed when creating the ID/Bone fields */
uiItemR(col, &dtar2_ptr, "transform_space", 0, NULL, ICON_NONE);
}
@@ -565,11 +573,12 @@ 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:"));
if (dtar->id && 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);
}
@@ -623,7 +632,7 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
if (driver->type == DRIVER_TYPE_PYTHON) {
/* expression */
uiItemR(col, &driver_ptr, "expression", 0, IFACE_("Expr"), ICON_NONE);
-
+
/* errors? */
if (driver->flag & DRIVER_FLAG_INVALID)
uiItemL(col, IFACE_("ERROR: Invalid Python expression"), ICON_ERROR);
@@ -668,19 +677,19 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
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 */
uiBlockSetEmboss(block, UI_EMBOSSN);
but = uiDefIconBut(block, 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"));
uiButSetFunc(but, driver_delete_var_cb, driver, dvar);
uiBlockSetEmboss(block, UI_EMBOSS);
-
+
/* variable type */
row = uiLayoutRow(box, FALSE);
uiItemR(row, &dvar_ptr, "type", 0, "", ICON_NONE);
@@ -721,7 +730,7 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
else {
BLI_snprintf(valBuf, sizeof(valBuf), "%.3f", dvar->curval);
}
-
+
uiItemL(row, valBuf, ICON_NONE);
}
}
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 01364fcacf0..6237958e723 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -82,36 +82,36 @@ static void image_info(Scene *scene, ImageUser *iuser, Image *ima, ImBuf *ibuf,
if (ima == NULL) return;
if (ibuf == NULL) {
- ofs += sprintf(str, "%s", IFACE_("Can't Load Image"));
+ ofs += sprintf(str, IFACE_("Can't Load Image"));
}
else {
if (ima->source == IMA_SRC_MOVIE) {
- ofs += sprintf(str, "%s", IFACE_("Movie"));
+ ofs += sprintf(str, IFACE_("Movie"));
if (ima->anim)
- ofs += sprintf(str + ofs, IFACE_("%d frs"), IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN));
+ ofs += sprintf(str + ofs, IFACE_(" %d frs"), IMB_anim_get_duration(ima->anim, IMB_TC_RECORD_RUN));
}
else
- ofs += sprintf(str, "%s", IFACE_("Image"));
+ ofs += sprintf(str, IFACE_("Image"));
- ofs += sprintf(str + ofs, ": %s %d x %d,", IFACE_("size"), ibuf->x, ibuf->y);
+ ofs += sprintf(str + ofs, IFACE_(": size %d x %d,"), ibuf->x, ibuf->y);
if (ibuf->rect_float) {
if (ibuf->channels != 4) {
- ofs += sprintf(str + ofs, "%d %s", ibuf->channels, IFACE_("float channel(s)"));
+ ofs += sprintf(str + ofs, IFACE_("%d float channel(s)"), ibuf->channels);
}
else if (ibuf->planes == R_IMF_PLANES_RGBA)
- ofs += sprintf(str + ofs, "%s", IFACE_(" RGBA float"));
+ ofs += sprintf(str + ofs, IFACE_(" RGBA float"));
else
- ofs += sprintf(str + ofs, "%s", IFACE_(" RGB float"));
+ ofs += sprintf(str + ofs, IFACE_(" RGB float"));
}
else {
if (ibuf->planes == R_IMF_PLANES_RGBA)
- ofs += sprintf(str + ofs, "%s", IFACE_(" RGBA byte"));
+ ofs += sprintf(str + ofs, IFACE_(" RGBA byte"));
else
- ofs += sprintf(str + ofs, "%s", IFACE_(" RGB byte"));
+ ofs += sprintf(str + ofs, IFACE_(" RGB byte"));
}
if (ibuf->zbuf || ibuf->zbuf_float)
- ofs += sprintf(str + ofs, "%s", IFACE_(" + Z"));
+ ofs += sprintf(str + ofs, IFACE_(" + Z"));
if (ima->source == IMA_SRC_SEQUENCE) {
char *file = BLI_last_slash(ibuf->name);
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index f86e59c41a8..5184b1e1a73 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -87,8 +87,6 @@ void IMAGE_OT_sample(struct wmOperatorType *ot);
void IMAGE_OT_sample_line(struct wmOperatorType *ot);
void IMAGE_OT_curves_point_set(struct wmOperatorType *ot);
-void IMAGE_OT_record_composite(struct wmOperatorType *ot);
-
/* image_panels.c */
struct ImageUser *ntree_get_active_iuser(struct bNodeTree *ntree);
void image_buttons_register(struct ARegionType *art);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index dc834d88323..b913b3528ac 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1959,9 +1959,10 @@ static int image_pack_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)
ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
if (!as_png && (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))) {
- pup = uiPupMenuBegin(C, "OK", ICON_QUESTION);
+ pup = uiPupMenuBegin(C, IFACE_("OK"), ICON_QUESTION);
layout = uiPupMenuLayout(pup);
- uiItemBooleanO(layout, "Can't pack edited image from disk. Pack as internal PNG?", ICON_NONE, op->idname, "as_png", 1);
+ uiItemBooleanO(layout, IFACE_("Can't pack edited image from disk, pack as internal PNG?"), ICON_NONE,
+ op->idname, "as_png", 1);
uiPupMenuEnd(C, pup);
BKE_image_release_ibuf(ima, ibuf, NULL);
@@ -2438,6 +2439,7 @@ void IMAGE_OT_curves_point_set(wmOperatorType *ot)
RNA_def_enum(ot->srna, "point", point_items, 0, "Point", "Set black point or white point for curves");
}
+#if 0 /* Not ported to 2.5x yet */
/******************** record composite operator *********************/
typedef struct RecordCompositeData {
@@ -2589,6 +2591,8 @@ void IMAGE_OT_record_composite(wmOperatorType *ot)
ot->poll = space_image_buffer_exists_poll;
}
+#endif
+
/********************* cycle render slot operator *********************/
static int image_cycle_render_slot_poll(bContext *C)
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index ca8270ba0f5..d82a46e9578 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -253,8 +253,6 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_sample_line);
WM_operatortype_append(IMAGE_OT_curves_point_set);
- WM_operatortype_append(IMAGE_OT_record_composite);
-
WM_operatortype_append(IMAGE_OT_properties);
WM_operatortype_append(IMAGE_OT_scopes);
}
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index 22668a3de3a..04f6a5152e6 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -40,9 +40,11 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
-#include "BKE_bpath.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
+#include "BKE_bpath.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -218,9 +220,9 @@ static int unpack_all_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)
}
if (count == 1)
- strcpy(title, "Unpack 1 file");
+ strcpy(title, IFACE_("Unpack 1 File"));
else
- BLI_snprintf(title, sizeof(title), "Unpack %d files", count);
+ BLI_snprintf(title, sizeof(title), IFACE_("Unpack %d Files"), count);
pup = uiPupMenuBegin(C, title, ICON_NONE);
layout = uiPupMenuLayout(pup);
@@ -291,7 +293,7 @@ static int unpack_item_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event
uiPopupMenu *pup;
uiLayout *layout;
- pup = uiPupMenuBegin(C, "Unpack", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Unpack"), ICON_NONE);
layout = uiPupMenuLayout(pup);
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index 5a8a77f7350..976769752f9 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -367,9 +367,9 @@ static void stats_string(Scene *scene)
mmap_in_use = MEM_get_mapped_memory_in_use();
/* get memory statistics */
- s = memstr + sprintf(memstr, " | Mem:%.2fM", (double)((mem_in_use - mmap_in_use) >> 10) / 1024.0);
+ s = memstr + sprintf(memstr, IFACE_(" | Mem:%.2fM"), (double)((mem_in_use - mmap_in_use) >> 10) / 1024.0);
if (mmap_in_use)
- sprintf(s, " (%.2fM)", (double)((mmap_in_use) >> 10) / 1024.0);
+ sprintf(s, IFACE_(" (%.2fM)"), (double)((mmap_in_use) >> 10) / 1024.0);
s = stats->infostr;
@@ -377,32 +377,32 @@ static void stats_string(Scene *scene)
if (scene->obedit) {
if (BKE_keyblock_from_object(scene->obedit))
- s += sprintf(s, "(Key) ");
+ s += sprintf(s, IFACE_("(Key) "));
if (scene->obedit->type == OB_MESH) {
- s += sprintf(s, "Verts:%d/%d | Edges:%d/%d | Faces:%d/%d | Tris:%d",
+ s += sprintf(s, IFACE_("Verts:%d/%d | Edges:%d/%d | Faces:%d/%d | Tris:%d"),
stats->totvertsel, stats->totvert, stats->totedgesel, stats->totedge, stats->totfacesel,
stats->totface, stats->tottri);
}
else if (scene->obedit->type == OB_ARMATURE) {
- s += sprintf(s, "Verts:%d/%d | Bones:%d/%d", stats->totvertsel, stats->totvert, stats->totbonesel,
+ s += sprintf(s, IFACE_("Verts:%d/%d | Bones:%d/%d"), stats->totvertsel, stats->totvert, stats->totbonesel,
stats->totbone);
}
else {
- s += sprintf(s, "Verts:%d/%d", stats->totvertsel, stats->totvert);
+ s += sprintf(s, IFACE_("Verts:%d/%d"), stats->totvertsel, stats->totvert);
}
strcat(s, memstr);
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
- s += sprintf(s, "Bones:%d/%d %s",
+ s += sprintf(s, IFACE_("Bones:%d/%d %s"),
stats->totbonesel, stats->totbone, memstr);
}
else if (stats_is_object_dynamic_topology_sculpt(ob)) {
- s += sprintf(s, "Verts:%d | Tris:%d", stats->totvert, stats->tottri);
+ s += sprintf(s, IFACE_("Verts:%d | Tris:%d"), stats->totvert, stats->tottri);
}
else {
- s += sprintf(s, "Verts:%d | Faces:%d | Tris:%d | Objects:%d/%d | Lamps:%d/%d%s",
+ s += sprintf(s, IFACE_("Verts:%d | Faces:%d | Tris:%d | Objects:%d/%d | Lamps:%d/%d%s"),
stats->totvert, stats->totface, stats->tottri, stats->totobjsel, stats->totobj, stats->totlampsel,
stats->totlamp, memstr);
}
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index e2eb1f030b3..31c773e613e 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -311,7 +311,7 @@ static void nla_panel_properties(const bContext *C, Panel *pa)
/* strip extents */
column = uiLayoutColumn(layout, TRUE);
- uiItemL(column, "Strip Extents:", ICON_NONE);
+ uiItemL(column, IFACE_("Strip Extents:"), ICON_NONE);
uiItemR(column, &strip_ptr, "frame_start", 0, NULL, ICON_NONE);
uiItemR(column, &strip_ptr, "frame_end", 0, NULL, ICON_NONE);
@@ -346,7 +346,7 @@ static void nla_panel_properties(const bContext *C, Panel *pa)
/* settings */
column = uiLayoutColumn(layout, TRUE);
uiLayoutSetActive(column, !(RNA_boolean_get(&strip_ptr, "use_animated_influence") || RNA_boolean_get(&strip_ptr, "use_animated_time")));
- uiItemL(column, "Playback Settings:", ICON_NONE);
+ uiItemL(column, IFACE_("Playback Settings:"), ICON_NONE);
uiItemR(column, &strip_ptr, "mute", 0, NULL, ICON_NONE);
uiItemR(column, &strip_ptr, "use_reverse", 0, NULL, ICON_NONE);
}
@@ -376,15 +376,15 @@ static void nla_panel_actclip(const bContext *C, Panel *pa)
/* action extents */
// XXX custom names were used here (to avoid the prefixes)... probably not necessary in future?
column = uiLayoutColumn(layout, TRUE);
- uiItemL(column, "Action Extents:", ICON_NONE);
- uiItemR(column, &strip_ptr, "action_frame_start", 0, "Start Frame", ICON_NONE);
- uiItemR(column, &strip_ptr, "action_frame_end", 0, "End Frame", ICON_NONE);
+ uiItemL(column, IFACE_("Action Extents:"), ICON_NONE);
+ uiItemR(column, &strip_ptr, "action_frame_start", 0, IFACE_("Start Frame"), ICON_NONE);
+ uiItemR(column, &strip_ptr, "action_frame_end", 0, IFACE_("End Frame"), ICON_NONE);
uiItemO(column, NULL, ICON_NONE, "NLA_OT_action_sync_length");
/* action usage */
column = uiLayoutColumn(layout, TRUE);
uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "use_animated_time") == FALSE);
- uiItemL(column, "Playback Settings:", ICON_NONE);
+ uiItemL(column, IFACE_("Playback Settings:"), ICON_NONE);
uiItemR(column, &strip_ptr, "scale", 0, NULL, ICON_NONE);
uiItemR(column, &strip_ptr, "repeat", 0, NULL, ICON_NONE);
}
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 3740c3fae5e..484eb47fa8e 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -44,6 +44,8 @@
#include "BLI_rand.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "BKE_action.h"
#include "BKE_fcurve.h"
#include "BKE_nla.h"
@@ -1951,7 +1953,7 @@ static int nla_fmodifier_add_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent
uiLayout *layout;
int i;
- pup = uiPupMenuBegin(C, "Add F-Modifier", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Add F-Modifier"), ICON_NONE);
layout = uiPupMenuLayout(pup);
/* start from 1 to skip the 'Invalid' modifier type */
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index b211bca4c0a..8a2e03f2660 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -1131,8 +1131,8 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(
/* skip if out of view */
if (node->totr.xmax < ar->v2d.cur.xmin || node->totr.xmin > ar->v2d.cur.xmax ||
- node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax) {
-
+ node->totr.ymax < ar->v2d.cur.ymin || node->totr.ymin > ar->v2d.cur.ymax)
+ {
uiEndBlock(C, node->block);
node->block = NULL;
return;
@@ -1608,12 +1608,15 @@ static void node_composit_buts_image_details(uiLayout *layout, bContext *C, Poin
node_composit_buts_image(layout, C, ptr);
+ uiItemR(layout, ptr, "use_straight_alpha_output", 0, NULL, 0);
+
if (!node->id)
return;
imaptr = RNA_pointer_get(ptr, "image");
uiTemplateColorspaceSettings(layout, &imaptr, "colorspace_settings");
+ uiItemR(layout, &imaptr, "alpha_mode", 0, NULL, 0);
}
static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, PointerRNA *ptr)
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index 22631568d03..4943bb45113 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -307,6 +307,7 @@ void NODE_OT_add_reroute(wmOperatorType *ot)
ot->name = "Add Reroute";
ot->idname = "NODE_OT_add_reroute";
+ ot->description = "Add a reroute node";
ot->invoke = WM_gesture_lines_invoke;
ot->modal = WM_gesture_lines_modal;
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index 943f12c4c54..7b7b98f132c 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -42,6 +42,8 @@
#include "BLI_rect.h"
#include "BLI_math.h"
+#include "BLF_translation.h"
+
#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
@@ -789,7 +791,7 @@ static int node_group_separate_exec(bContext *C, wmOperator *op)
static int node_group_separate_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
{
- uiPopupMenu *pup = uiPupMenuBegin(C, "Separate", ICON_NONE);
+ uiPopupMenu *pup = uiPupMenuBegin(C, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Separate"), ICON_NONE);
uiLayout *layout = uiPupMenuLayout(pup);
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
@@ -1148,7 +1150,7 @@ static int node_group_make_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *act = nodeGetActive(snode->edittree);
- uiPopupMenu *pup = uiPupMenuBegin(C, "Make Group", ICON_NONE);
+ uiPopupMenu *pup = uiPupMenuBegin(C, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Make Group"), ICON_NONE);
uiLayout *layout = uiPupMenuLayout(pup);
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 303782f3fbd..cd04c8c6bd1 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -389,7 +389,7 @@ static void group_linkobs2scene_cb(bContext *UNUSED(C), Scene *scene, TreeElemen
/* link to scene */
base = MEM_callocN(sizeof(Base), "add_base");
BLI_addhead(&scene->base, base);
- base->lay = (1 << 20) - 1; /*v3d->lay;*/ /* would be nice to use the 3d layer but the include's not here */
+ base->lay = gob->ob->lay;
gob->ob->flag |= SELECT;
base->flag = gob->ob->flag;
base->object = gob->ob;
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 29a6a1f6d50..78a76532487 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -126,23 +126,50 @@ static void sequencer_generic_invoke_path__internal(bContext *C, wmOperator *op,
}
}
-static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, wmEvent *event, int flag)
+static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type)
{
- View2D *v2d = UI_view2d_fromcontext(C);
-
- float mval_v2d[2];
+ Sequence *tgt = NULL;
+ Sequence *seq;
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = BKE_sequencer_editing_get(scene, TRUE);
+ int cfra = (int) CFRA;
+ int proximity = INT_MAX;
+
+ if (!ed || !ed->seqbasep) {
+ return 1;
+ }
+
+ for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if ((type == -1 || seq->type == type) &&
+ (seq->enddisp < cfra) &&
+ (cfra - seq->enddisp < proximity))
+ {
+ tgt = seq;
+ proximity = cfra - seq->enddisp;
+ }
+ }
- UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mval_v2d[0], &mval_v2d[1]);
+ if (tgt) {
+ return tgt->machine;
+ }
+ return 1;
+}
+static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, int flag, int type)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ int cfra = (int) CFRA;
+
/* effect strips don't need a channel initialized from the mouse */
if (!(flag & SEQPROP_NOCHAN)) {
- RNA_int_set(op->ptr, "channel", (int)mval_v2d[1] + 0.5f);
+ RNA_int_set(op->ptr, "channel", sequencer_generic_invoke_xy_guess_channel(C, type));
}
- RNA_int_set(op->ptr, "frame_start", (int)mval_v2d[0]);
+ RNA_int_set(op->ptr, "frame_start", cfra);
if ((flag & SEQPROP_ENDFRAME) && RNA_struct_property_is_set(op->ptr, "frame_end") == 0)
- RNA_int_set(op->ptr, "frame_end", (int)mval_v2d[0] + 25); // XXX arbitary but ok for now.
+ RNA_int_set(op->ptr, "frame_end", cfra + 25); // XXX arbitary but ok for now.
if (!(flag & SEQPROP_NOPATHS)) {
sequencer_generic_invoke_path__internal(C, op, "filepath");
@@ -277,7 +304,7 @@ static int sequencer_add_scene_strip_invoke(bContext *C, wmOperator *op, wmEvent
if (!RNA_struct_property_is_set(op->ptr, "scene"))
return WM_enum_search_invoke(C, op, event);
- sequencer_generic_invoke_xy__internal(C, op, event, 0);
+ sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_SCENE);
return sequencer_add_scene_strip_exec(C, op);
// needs a menu
// return WM_menu_invoke(C, op, event);
@@ -375,7 +402,7 @@ static int sequencer_add_movieclip_strip_invoke(bContext *C, wmOperator *op, wmE
if (!RNA_struct_property_is_set(op->ptr, "clip"))
return WM_enum_search_invoke(C, op, event);
- sequencer_generic_invoke_xy__internal(C, op, event, 0);
+ sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_MOVIECLIP);
return sequencer_add_movieclip_strip_exec(C, op);
// needs a menu
// return WM_menu_invoke(C, op, event);
@@ -472,7 +499,7 @@ static int sequencer_add_mask_strip_invoke(bContext *C, wmOperator *op, wmEvent
if (!RNA_struct_property_is_set(op->ptr, "mask"))
return WM_enum_search_invoke(C, op, event);
- sequencer_generic_invoke_xy__internal(C, op, event, 0);
+ sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_MASK);
return sequencer_add_mask_strip_exec(C, op);
// needs a menu
// return WM_menu_invoke(C, op, event);
@@ -575,7 +602,7 @@ static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op)
}
-static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
{
if (!ED_operator_sequencer_active(C)) {
@@ -587,11 +614,11 @@ static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, wmEvent
if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath"))
{
- sequencer_generic_invoke_xy__internal(C, op, event, SEQPROP_NOPATHS);
+ sequencer_generic_invoke_xy__internal(C, op, SEQPROP_NOPATHS, SEQ_TYPE_MOVIE);
return sequencer_add_movie_strip_exec(C, op);
}
- sequencer_generic_invoke_xy__internal(C, op, event, 0);
+ sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_MOVIE);
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -630,7 +657,7 @@ static int sequencer_add_sound_strip_exec(bContext *C, wmOperator *op)
return sequencer_add_generic_strip_exec(C, op, BKE_sequencer_add_sound_strip);
}
-static int sequencer_add_sound_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sequencer_add_sound_strip_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
{
if (!ED_operator_sequencer_active(C)) {
@@ -642,11 +669,11 @@ static int sequencer_add_sound_strip_invoke(bContext *C, wmOperator *op, wmEvent
if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath"))
{
- sequencer_generic_invoke_xy__internal(C, op, event, SEQPROP_NOPATHS);
+ sequencer_generic_invoke_xy__internal(C, op, SEQPROP_NOPATHS, SEQ_TYPE_SOUND_RAM);
return sequencer_add_sound_strip_exec(C, op);
}
- sequencer_generic_invoke_xy__internal(C, op, event, 0);
+ sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_SOUND_RAM);
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -742,7 +769,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
{
if (!ED_operator_sequencer_active(C)) {
@@ -753,11 +780,11 @@ static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, wmEvent
/* drag drop has set the names */
if (RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) {
- sequencer_generic_invoke_xy__internal(C, op, event, SEQPROP_ENDFRAME | SEQPROP_NOPATHS);
+ sequencer_generic_invoke_xy__internal(C, op, SEQPROP_ENDFRAME | SEQPROP_NOPATHS, SEQ_TYPE_IMAGE);
return sequencer_add_image_strip_exec(C, op);
}
- sequencer_generic_invoke_xy__internal(C, op, event, SEQPROP_ENDFRAME);
+ sequencer_generic_invoke_xy__internal(C, op, SEQPROP_ENDFRAME, SEQ_TYPE_IMAGE);
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -894,7 +921,7 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
/* add color */
-static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
{
short is_type_set = RNA_struct_property_is_set(op->ptr, "type");
int type = -1;
@@ -917,7 +944,7 @@ static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, wmEven
}
}
- sequencer_generic_invoke_xy__internal(C, op, event, prop_flag);
+ sequencer_generic_invoke_xy__internal(C, op, prop_flag, type);
return sequencer_add_effect_strip_exec(C, op);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 249ba986fd3..396878cbfeb 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -1059,8 +1059,10 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, ibuf->x, ibuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, display_buffer);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ if (sseq->flag & SEQ_USE_ALPHA) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
glBegin(GL_QUADS);
@@ -1093,7 +1095,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);
- glDisable(GL_BLEND);
+ if (sseq->flag & SEQ_USE_ALPHA)
+ glDisable(GL_BLEND);
glDeleteTextures(1, &texid);
if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index d541e1d6c07..4c6b909882c 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -120,7 +120,7 @@ static SpaceLink *sequencer_new(const bContext *C)
sseq->chanshown = 0;
sseq->view = SEQ_VIEW_SEQUENCE;
sseq->mainb = SEQ_DRAW_IMG_IMBUF;
- sseq->flag = SEQ_SHOW_GPENCIL;
+ sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA;
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for sequencer");
diff --git a/source/blender/editors/space_text/text_format.c b/source/blender/editors/space_text/text_format.c
index a8c2de193c4..3c7897200ed 100644
--- a/source/blender/editors/space_text/text_format.c
+++ b/source/blender/editors/space_text/text_format.c
@@ -157,7 +157,7 @@ void text_format_fill(const char **str_p, char **fmt_p, const char type, const i
*fmt++ = type;
str += size;
- i += size;
+ i += 1;
}
str--;
diff --git a/source/blender/editors/space_text/text_header.c b/source/blender/editors/space_text/text_header.c
index 52253b2d5d2..605a08e587a 100644
--- a/source/blender/editors/space_text/text_header.c
+++ b/source/blender/editors/space_text/text_header.c
@@ -42,6 +42,8 @@
#include "BLI_blenlib.h"
+#include "BLF_translation.h"
+
#include "BKE_context.h"
#include "BKE_screen.h"
@@ -120,7 +122,7 @@ void TEXT_OT_properties(wmOperatorType *ot)
uiPopupMenu *pup;
if (text) {
- pup = uiPupMenuBegin(C, "Text", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Text"), ICON_NONE);
if (txt_has_sel(text)) {
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_cut");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_copy");
@@ -134,7 +136,7 @@ void TEXT_OT_properties(wmOperatorType *ot)
uiPupMenuEnd(C, pup);
}
else {
- pup = uiPupMenuBegin(C, "File", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("File"), ICON_NONE);
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open");
uiPupMenuEnd(C, pup);
@@ -146,7 +148,7 @@ void TEXT_OT_properties(wmOperatorType *ot)
uiPopupMenu *pup;
- pup = uiPupMenuBegin(C, "Edit", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Edit"), ICON_NONE);
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_cut");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_copy");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_paste");
@@ -159,7 +161,7 @@ void TEXT_OT_properties(wmOperatorType *ot)
uiPopupMenu *pup;
if (text) {
- pup = uiPupMenuBegin(C, "Text", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Text"), ICON_NONE);
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_save");
@@ -168,7 +170,7 @@ void TEXT_OT_properties(wmOperatorType *ot)
uiPupMenuEnd(C, pup);
}
else {
- pup = uiPupMenuBegin(C, "File", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("File"), ICON_NONE);
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_new");
uiItemO(layout, NULL, ICON_NONE, "TEXT_OT_open");
uiPupMenuEnd(C, pup);
@@ -180,11 +182,14 @@ void TEXT_OT_properties(wmOperatorType *ot)
uiPopupMenu *pup;
- pup = uiPupMenuBegin(C, "Text", ICON_NONE);
- uiItemEnumO(layout, "TEXT_OT_move", "Top of File", 0, "type", FILE_TOP);
- uiItemEnumO(layout, "TEXT_OT_move", "Bottom of File", 0, "type", FILE_BOTTOM);
- uiItemEnumO(layout, "TEXT_OT_move", "Page Up", 0, "type", PREV_PAGE);
- uiItemEnumO(layout, "TEXT_OT_move", "Page Down", 0, "type", NEXT_PAGE);
+ pup = uiPupMenuBegin(C, IFACE_("Text"), ICON_NONE);
+ uiItemEnumO(layout, "TEXT_OT_move", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Top of File"),
+ 0, "type", FILE_TOP);
+ uiItemEnumO(layout, "TEXT_OT_move", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Bottom of File"),
+ 0, "type", FILE_BOTTOM);
+ uiItemEnumO(layout, "TEXT_OT_move", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Page Up"), 0, "type", PREV_PAGE);
+ uiItemEnumO(layout, "TEXT_OT_move", CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Page Down"),
+ 0, "type", NEXT_PAGE);
uiPupMenuEnd(C, pup);
}
#endif
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index 9b5d453d8a3..b45961bff11 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -3110,27 +3110,31 @@ static int text_resolve_conflict_invoke(bContext *C, wmOperator *op, wmEvent *UN
case 1:
if (text->flags & TXT_ISDIRTY) {
/* modified locally and externally, ahhh. offer more possibilites. */
- pup = uiPupMenuBegin(C, "File Modified Outside and Inside Blender", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("File Modified Outside and Inside Blender"), ICON_NONE);
layout = uiPupMenuLayout(pup);
- uiItemEnumO_ptr(layout, op->type, "Reload from disk (ignore local changes)", 0, "resolution", RESOLVE_RELOAD);
- uiItemEnumO_ptr(layout, op->type, "Save to disk (ignore outside changes)", 0, "resolution", RESOLVE_SAVE);
- uiItemEnumO_ptr(layout, op->type, "Make text internal (separate copy)", 0, "resolution", RESOLVE_MAKE_INTERNAL);
+ uiItemEnumO_ptr(layout, op->type, IFACE_("Reload from disk (ignore local changes)"),
+ 0, "resolution", RESOLVE_RELOAD);
+ uiItemEnumO_ptr(layout, op->type, IFACE_("Save to disk (ignore outside changes)"),
+ 0, "resolution", RESOLVE_SAVE);
+ uiItemEnumO_ptr(layout, op->type, IFACE_("Make text internal (separate copy)"),
+ 0, "resolution", RESOLVE_MAKE_INTERNAL);
uiPupMenuEnd(C, pup);
}
else {
- pup = uiPupMenuBegin(C, "File Modified Outside Blender", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("File Modified Outside Blender"), ICON_NONE);
layout = uiPupMenuLayout(pup);
- uiItemEnumO_ptr(layout, op->type, "Reload from disk", 0, "resolution", RESOLVE_RELOAD);
- uiItemEnumO_ptr(layout, op->type, "Make text internal (separate copy)", 0, "resolution", RESOLVE_MAKE_INTERNAL);
- uiItemEnumO_ptr(layout, op->type, "Ignore", 0, "resolution", RESOLVE_IGNORE);
+ uiItemEnumO_ptr(layout, op->type, IFACE_("Reload from disk"), 0, "resolution", RESOLVE_RELOAD);
+ uiItemEnumO_ptr(layout, op->type, IFACE_("Make text internal (separate copy)"),
+ 0, "resolution", RESOLVE_MAKE_INTERNAL);
+ uiItemEnumO_ptr(layout, op->type, IFACE_("Ignore"), 0, "resolution", RESOLVE_IGNORE);
uiPupMenuEnd(C, pup);
}
break;
case 2:
- pup = uiPupMenuBegin(C, "File Deleted Outside Blender", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("File Deleted Outside Blender"), ICON_NONE);
layout = uiPupMenuLayout(pup);
- uiItemEnumO_ptr(layout, op->type, "Make text internal", 0, "resolution", RESOLVE_MAKE_INTERNAL);
- uiItemEnumO_ptr(layout, op->type, "Recreate file", 0, "resolution", RESOLVE_SAVE);
+ uiItemEnumO_ptr(layout, op->type, IFACE_("Make text internal"), 0, "resolution", RESOLVE_MAKE_INTERNAL);
+ uiItemEnumO_ptr(layout, op->type, IFACE_("Recreate file"), 0, "resolution", RESOLVE_SAVE);
uiPupMenuEnd(C, pup);
break;
}
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index fc8d5d26455..32d961ab64c 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -623,16 +623,17 @@ static void draw_empty_image(Object *ob, const short dflag, const unsigned char
if ((dflag & DRAW_CONSTCOLOR) == 0) {
glColor3ubv(ob_wire_col);
-
- /* Calculate the outline vertex positions */
- glBegin(GL_LINE_LOOP);
- glVertex2f(ofs_x, ofs_y);
- glVertex2f(ofs_x + ima_x, ofs_y);
- glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
- glVertex2f(ofs_x, ofs_y + ima_y);
- glEnd();
}
+ /* Calculate the outline vertex positions */
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(ofs_x, ofs_y);
+ glVertex2f(ofs_x + ima_x, ofs_y);
+ glVertex2f(ofs_x + ima_x, ofs_y + ima_y);
+ glVertex2f(ofs_x, ofs_y + ima_y);
+ glEnd();
+
+
/* Reset GL settings */
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 658196a1bd4..57755231240 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -513,20 +513,34 @@ static int view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUS
return 0;
}
-
static int view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
{
- if (ED_view3d_give_base_under_cursor(C, event->mval) ) {
- return 0;
+ if (event->ctrl)
+ return false;
+
+ if (!ED_view3d_give_base_under_cursor(C, event->mval)) {
+ return view3d_ima_drop_poll(C, drag, event);
}
- return view3d_ima_drop_poll(C, drag, event);
+ return 0;
}
-static int view3d_ima_ob_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
+static int view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
{
- if (ED_view3d_give_base_under_cursor(C, event->mval) ) {
+ Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
+
+ /* either holding and ctrl and no object, or dropping to empty */
+ if ((event->ctrl && !base) || (base && base->object->type == OB_EMPTY))
+ return view3d_ima_drop_poll(C, drag, event);
+
+ return 0;
+}
+
+static int view3d_ima_mesh_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
+{
+ Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
+
+ if (base && base->object->type == OB_MESH)
return view3d_ima_drop_poll(C, drag, event);
- }
return 0;
}
@@ -570,7 +584,8 @@ static void view3d_dropboxes(void)
WM_dropbox_add(lb, "OBJECT_OT_add_named", view3d_ob_drop_poll, view3d_ob_drop_copy);
WM_dropbox_add(lb, "OBJECT_OT_drop_named_material", view3d_mat_drop_poll, view3d_id_drop_copy);
- WM_dropbox_add(lb, "MESH_OT_drop_named_image", view3d_ima_ob_drop_poll, view3d_id_path_drop_copy);
+ WM_dropbox_add(lb, "MESH_OT_drop_named_image", view3d_ima_mesh_drop_poll, view3d_id_path_drop_copy);
+ WM_dropbox_add(lb, "OBJECT_OT_drop_named_image", view3d_ima_empty_drop_poll, view3d_id_path_drop_copy);
WM_dropbox_add(lb, "VIEW3D_OT_background_image_add", view3d_ima_bg_drop_poll, view3d_id_path_drop_copy);
WM_dropbox_add(lb, "OBJECT_OT_group_instance_add", view3d_group_drop_poll, view3d_group_drop_copy);
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 30ed7a57f9d..5f54f0dcfc8 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -996,12 +996,12 @@ void VIEW3D_OT_rotate(wmOperatorType *ot)
/* NDOF utility functions
* (should these functions live in this file?)
*/
-float ndof_to_axis_angle(struct wmNDOFMotionData *ndof, float axis[3])
+float ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3])
{
return ndof->dt * normalize_v3_v3(axis, ndof->rvec);
}
-void ndof_to_quat(struct wmNDOFMotionData *ndof, float q[4])
+void ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4])
{
float axis[3];
float angle;
@@ -1010,6 +1010,84 @@ void ndof_to_quat(struct wmNDOFMotionData *ndof, float q[4])
axis_angle_to_quat(q, axis, angle);
}
+static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, RegionView3D *rv3d, const float view_inv[4],
+ const float rot_sensitivity, const float dt,
+ /* optional, can be NULL*/
+ ViewOpsData *vod)
+{
+ if (U.ndof_flag & NDOF_TURNTABLE) {
+
+ /* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
+ float angle, rot[4];
+ float xvec[3] = {1, 0, 0};
+
+ /* Determine the direction of the x vector (for rotating up and down) */
+ mul_qt_v3(view_inv, xvec);
+
+ /* Perform the up/down rotation */
+ angle = rot_sensitivity * dt * ndof->rx;
+ if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
+ angle = -angle;
+ rot[0] = cosf(angle);
+ mul_v3_v3fl(rot + 1, xvec, sin(angle));
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
+
+ /* Perform the orbital rotation */
+ angle = rot_sensitivity * dt * ndof->ry;
+ if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
+ angle = -angle;
+
+ /* update the onscreen doo-dad */
+ rv3d->rot_angle = angle;
+ rv3d->rot_axis[0] = 0;
+ rv3d->rot_axis[1] = 0;
+ rv3d->rot_axis[2] = 1;
+
+ rot[0] = cosf(angle);
+ rot[1] = rot[2] = 0.0;
+ rot[3] = sinf(angle);
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
+
+ }
+ else {
+ float rot[4];
+ float axis[3];
+ float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis);
+
+ if (U.ndof_flag & NDOF_ROLL_INVERT_AXIS) axis[2] = -axis[2];
+ if (U.ndof_flag & NDOF_TILT_INVERT_AXIS) axis[0] = -axis[0];
+ if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS) axis[1] = -axis[1];
+
+
+ /* transform rotation axis from view to world coordinates */
+ mul_qt_v3(view_inv, axis);
+
+ /* update the onscreen doo-dad */
+ rv3d->rot_angle = angle;
+ copy_v3_v3(rv3d->rot_axis, axis);
+
+ axis_angle_to_quat(rot, axis, angle);
+
+ /* apply rotation */
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
+ }
+
+ /* rotate around custom center */
+ if (vod && vod->use_dyn_ofs) {
+ float q1[4];
+
+ /* compute the post multiplication quat, to rotate the offset correctly */
+ conjugate_qt_qt(q1, vod->oldquat);
+ mul_qt_qtqt(q1, q1, rv3d->viewquat);
+
+ conjugate_qt(q1); /* conj == inv for unit quat */
+ copy_v3_v3(rv3d->ofs, vod->ofs);
+ sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
+ mul_qt_v3(q1, rv3d->ofs);
+ add_v3_v3(rv3d->ofs, vod->dyn_ofs);
+ }
+}
+
/* -- "orbit" navigation (trackball/turntable)
* -- zooming
* -- panning in rotationally-locked views
@@ -1065,86 +1143,8 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
if (has_rotation) {
-
rv3d->view = RV3D_VIEW_USER;
-
- if (U.ndof_flag & NDOF_TURNTABLE) {
-
- /* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
- float angle, rot[4];
- float xvec[3] = {1, 0, 0};
-
- /* Determine the direction of the x vector (for rotating up and down) */
- mul_qt_v3(view_inv, xvec);
-
- /* Perform the up/down rotation */
- angle = rot_sensitivity * dt * ndof->rx;
- if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
- angle = -angle;
- rot[0] = cos(angle);
- mul_v3_v3fl(rot + 1, xvec, sin(angle));
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- /* Perform the orbital rotation */
- angle = rot_sensitivity * dt * ndof->ry;
- if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
- angle = -angle;
-
- /* update the onscreen doo-dad */
- rv3d->rot_angle = angle;
- rv3d->rot_axis[0] = 0;
- rv3d->rot_axis[1] = 0;
- rv3d->rot_axis[2] = 1;
-
- rot[0] = cos(angle);
- rot[1] = rot[2] = 0.0;
- rot[3] = sin(angle);
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- }
- else {
- float rot[4];
- float axis[3];
- float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis);
-
- if (U.ndof_flag & NDOF_ROLL_INVERT_AXIS)
- axis[2] = -axis[2];
-
- if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
- axis[0] = -axis[0];
-
- if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
- axis[1] = -axis[1];
-
-
- /* transform rotation axis from view to world coordinates */
- mul_qt_v3(view_inv, axis);
-
- /* update the onscreen doo-dad */
- rv3d->rot_angle = angle;
- copy_v3_v3(rv3d->rot_axis, axis);
-
- axis_angle_to_quat(rot, axis, angle);
-
- /* apply rotation */
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- }
-
- /* rotate around custom center */
- if (vod && vod->use_dyn_ofs) {
- float q1[4];
-
- /* compute the post multiplication quat, to rotate the offset correctly */
- conjugate_qt_qt(q1, vod->oldquat);
- mul_qt_qtqt(q1, q1, rv3d->viewquat);
-
- conjugate_qt(q1); /* conj == inv for unit quat */
- copy_v3_v3(rv3d->ofs, vod->ofs);
- sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
- mul_qt_v3(q1, rv3d->ofs);
- add_v3_v3(rv3d->ofs, vod->dyn_ofs);
- }
+ view3d_ndof_orbit(ndof, rv3d, view_inv, rot_sensitivity, dt, vod);
}
}
@@ -1239,86 +1239,8 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
}
if (has_rotation) {
-
rv3d->view = RV3D_VIEW_USER;
-
- if (U.ndof_flag & NDOF_TURNTABLE) {
-
- /* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
- float angle, rot[4];
- float xvec[3] = {1, 0, 0};
-
- /* Determine the direction of the x vector (for rotating up and down) */
- mul_qt_v3(view_inv, xvec);
-
- /* Perform the up/down rotation */
- angle = rot_sensitivity * dt * ndof->rx;
- if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
- angle = -angle;
- rot[0] = cos(angle);
- mul_v3_v3fl(rot + 1, xvec, sin(angle));
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- /* Perform the orbital rotation */
- angle = rot_sensitivity * dt * ndof->ry;
- if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
- angle = -angle;
-
- /* update the onscreen doo-dad */
- rv3d->rot_angle = angle;
- rv3d->rot_axis[0] = 0;
- rv3d->rot_axis[1] = 0;
- rv3d->rot_axis[2] = 1;
-
- rot[0] = cos(angle);
- rot[1] = rot[2] = 0.0;
- rot[3] = sin(angle);
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- }
- else {
- float rot[4];
- float axis[3];
- float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis);
-
- if (U.ndof_flag & NDOF_ROLL_INVERT_AXIS)
- axis[2] = -axis[2];
-
- if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
- axis[0] = -axis[0];
-
- if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
- axis[1] = -axis[1];
-
-
- /* transform rotation axis from view to world coordinates */
- mul_qt_v3(view_inv, axis);
-
- /* update the onscreen doo-dad */
- rv3d->rot_angle = angle;
- copy_v3_v3(rv3d->rot_axis, axis);
-
- axis_angle_to_quat(rot, axis, angle);
-
- /* apply rotation */
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- }
-
- /* rotate around custom center */
- if (vod && vod->use_dyn_ofs) {
- float q1[4];
-
- /* compute the post multiplication quat, to rotate the offset correctly */
- conjugate_qt_qt(q1, vod->oldquat);
- mul_qt_qtqt(q1, q1, rv3d->viewquat);
-
- conjugate_qt(q1); /* conj == inv for unit quat */
- copy_v3_v3(rv3d->ofs, vod->ofs);
- sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
- mul_qt_v3(q1, rv3d->ofs);
- add_v3_v3(rv3d->ofs, vod->dyn_ofs);
- }
+ view3d_ndof_orbit(ndof, rv3d, view_inv, rot_sensitivity, dt, vod);
}
}
@@ -1502,84 +1424,8 @@ static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
/* move center of view opposite of hand motion (this is camera mode, not object mode) */
sub_v3_v3(rv3d->ofs, pan_vec);
-
- if (U.ndof_flag & NDOF_TURNTABLE) {
- /* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
- float angle, rot[4];
- float xvec[3] = {1, 0, 0};
-
- /* Determine the direction of the x vector (for rotating up and down) */
- mul_qt_v3(view_inv, xvec);
-
- /* Perform the up/down rotation */
- angle = rot_sensitivity * dt * ndof->rx;
- if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
- angle = -angle;
- rot[0] = cos(angle);
- mul_v3_v3fl(rot + 1, xvec, sin(angle));
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- /* Perform the orbital rotation */
- angle = rot_sensitivity * dt * ndof->ry;
- if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
- angle = -angle;
-
- /* update the onscreen doo-dad */
- rv3d->rot_angle = angle;
- rv3d->rot_axis[0] = 0;
- rv3d->rot_axis[1] = 0;
- rv3d->rot_axis[2] = 1;
-
- rot[0] = cos(angle);
- rot[1] = rot[2] = 0.0;
- rot[3] = sin(angle);
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- }
- else {
-
- float rot[4];
- float axis[3];
- float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis);
-
- if (U.ndof_flag & NDOF_ROLL_INVERT_AXIS)
- axis[2] = -axis[2];
-
- if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
- axis[0] = -axis[0];
-
- if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
- axis[1] = -axis[1];
-
- /* transform rotation axis from view to world coordinates */
- mul_qt_v3(view_inv, axis);
-
- /* update the onscreen doo-dad */
- rv3d->rot_angle = angle;
- copy_v3_v3(rv3d->rot_axis, axis);
-
- axis_angle_to_quat(rot, axis, angle);
-
- /* apply rotation */
- mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
-
- }
-
- /* rotate around custom center */
- if (vod->use_dyn_ofs) {
- float q1[4];
-
- /* compute the post multiplication quat, to rotate the offset correctly */
- conjugate_qt_qt(q1, vod->oldquat);
- mul_qt_qtqt(q1, q1, rv3d->viewquat);
-
- conjugate_qt(q1); /* conj == inv for unit quat */
- copy_v3_v3(rv3d->ofs, vod->ofs);
- sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
- mul_qt_v3(q1, rv3d->ofs);
- add_v3_v3(rv3d->ofs, vod->dyn_ofs);
- }
+ view3d_ndof_orbit(ndof, rv3d, view_inv, rot_sensitivity, dt, vod);
}
viewops_data_free(C, op);
@@ -3699,7 +3545,9 @@ static int background_image_add_invoke(bContext *C, wmOperator *op, wmEvent *UNU
void VIEW3D_OT_background_image_add(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Add Background Image";
+ /* note: having key shortcut here is bad practice,
+ * but for now keep because this displays when dragging an image over the 3D viewport */
+ ot->name = "Add Background Image (Ctrl for Empty Object)";
ot->description = "Add a new background image";
ot->idname = "VIEW3D_OT_background_image_add";
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 2b30e4e6b81..e078fa8eda1 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -400,13 +400,13 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
block = uiLayoutGetBlock(row);
uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL,
0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0,
- "Vertex select - Shift-Click for multiple modes");
+ TIP_("Vertex select - Shift-Click for multiple modes"));
uiDefIconButBitS(block, TOG, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL,
0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0,
- "Edge select - Shift-Click for multiple modes, Ctrl-Click expands selection");
+ TIP_("Edge select - Shift-Click for multiple modes, Ctrl-Click expands selection"));
uiDefIconButBitS(block, TOG, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL,
0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0,
- "Face select - Shift-Click for multiple modes, Ctrl-Click expands selection");
+ TIP_("Face select - Shift-Click for multiple modes, Ctrl-Click expands selection"));
}
}
@@ -453,6 +453,13 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
if (obedit == NULL && is_paint) {
+
+ if (ob->mode & OB_MODE_WEIGHT_PAINT) {
+ /* Only for Weight Paint. makes no sense in other paint modes. */
+ row = uiLayoutRow(layout, TRUE);
+ uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
+ }
+
/* Manipulators aren't used in paint modes */
if (!ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_PARTICLE_EDIT)) {
/* masks aren't used for sculpt and particle painting */
@@ -476,7 +483,9 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
/* pose/object only however we want to allow in weight paint mode too
- * so don't be totally strict and just check not-editmode for now */
+ * so don't be totally strict and just check not-editmode for now
+ * XXX We never get here when we are in Weight Paint mode
+ */
if (obedit == NULL) {
uiItemR(row, &v3dptr, "use_pivot_point_align", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
}
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index c8f0fe44433..d4cfa9076a6 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -101,8 +101,8 @@ void VIEW3D_OT_clear_render_border(struct wmOperatorType *ot);
void VIEW3D_OT_zoom_border(struct wmOperatorType *ot);
void view3d_boxview_copy(ScrArea *sa, ARegion *ar);
-void ndof_to_quat(struct wmNDOFMotionData *ndof, float q[4]);
-float ndof_to_axis_angle(struct wmNDOFMotionData *ndof, float axis[3]);
+void ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4]);
+float ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3]);
/* view3d_fly.c */
void view3d_keymap(struct wmKeyConfig *keyconf);
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index c428cb02236..bc1656ff7c6 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -43,6 +43,7 @@
#include "ED_view3d.h" /* own include */
#define BL_NEAR_CLIP 0.001
+#define BL_ZERO_CLIP 0.001
/* Non Clipping Projection Functions
* ********************************* */
@@ -134,18 +135,25 @@ static eV3DProjStatus ed_view3d_project__internal(ARegion *ar,
vec4[3] = 1.0;
mul_m4_v4(perspmat, vec4);
- if (((flag & V3D_PROJ_TEST_CLIP_NEAR) == 0) || (vec4[3] > (float)BL_NEAR_CLIP)) {
- const float scalar = (vec4[3] != 0.0f) ? (1.0f / vec4[3]): 0.0f;
- const float fx = ((float)ar->winx / 2.0f) * (1.0f + (vec4[0] * scalar));
- if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fx > 0.0f && fx < (float)ar->winx)) {
- const float fy = ((float)ar->winy / 2.0f) * (1.0f + (vec4[1] * scalar));
- if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fy > 0.0f && fy < (float)ar->winy)) {
- r_co[0] = floorf(fx);
- r_co[1] = floorf(fy);
-
- /* check if the point is behind the view, we need to flip in this case */
- if (UNLIKELY((flag & V3D_PROJ_TEST_CLIP_NEAR) == 0) && (vec4[3] < 0.0f)) {
- negate_v2(r_co);
+
+
+ if (((flag & V3D_PROJ_TEST_CLIP_ZERO) == 0) || (fabsf(vec4[3]) > (float)BL_ZERO_CLIP)) {
+ if (((flag & V3D_PROJ_TEST_CLIP_NEAR) == 0) || (vec4[3] > (float)BL_NEAR_CLIP)) {
+ const float scalar = (vec4[3] != 0.0f) ? (1.0f / vec4[3]): 0.0f;
+ const float fx = ((float)ar->winx / 2.0f) * (1.0f + (vec4[0] * scalar));
+ if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fx > 0.0f && fx < (float)ar->winx)) {
+ const float fy = ((float)ar->winy / 2.0f) * (1.0f + (vec4[1] * scalar));
+ if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fy > 0.0f && fy < (float)ar->winy)) {
+ r_co[0] = floorf(fx);
+ r_co[1] = floorf(fy);
+
+ /* check if the point is behind the view, we need to flip in this case */
+ if (UNLIKELY((flag & V3D_PROJ_TEST_CLIP_NEAR) == 0) && (vec4[3] < 0.0f)) {
+ negate_v2(r_co);
+ }
+ }
+ else {
+ return V3D_PROJ_RET_CLIP_WIN;
}
}
else {
@@ -153,11 +161,11 @@ static eV3DProjStatus ed_view3d_project__internal(ARegion *ar,
}
}
else {
- return V3D_PROJ_RET_CLIP_WIN;
+ return V3D_PROJ_RET_CLIP_NEAR;
}
}
else {
- return V3D_PROJ_RET_CLIP_NEAR;
+ return V3D_PROJ_RET_CLIP_ZERO;
}
return V3D_PROJ_RET_OK;
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index dac887f7f13..24260898066 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -617,7 +617,8 @@ static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const
LassoSelectUserData *data = userData;
if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) {
+ BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED))
+ {
bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
}
}
@@ -717,7 +718,8 @@ static void do_lasso_select_mball__doSelectElem(void *userData, struct MetaElem
LassoSelectUserData *data = userData;
if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX)) {
+ BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX))
+ {
if (data->select) ml->flag |= SELECT;
else ml->flag &= ~SELECT;
data->is_change = TRUE;
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index ea82ebb9234..c8874d13cac 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -239,11 +239,11 @@ void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
}
}
-void projectIntView(TransInfo *t, const float vec[3], int adr[2])
+void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag)
{
if (t->spacetype == SPACE_VIEW3D) {
if (t->ar->regiontype == RGN_TYPE_WINDOW) {
- if (ED_view3d_project_int_global(t->ar, vec, adr, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
+ if (ED_view3d_project_int_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
adr[0] = (int)2140000000.0f; /* this is what was done in 2.64, perhaps we can be smarter? */
adr[1] = (int)2140000000.0f;
}
@@ -361,15 +361,19 @@ void projectIntView(TransInfo *t, const float vec[3], int adr[2])
UI_view2d_to_region_no_clip((View2D *)t->view, vec[0], vec[1], adr, adr + 1);
}
}
+void projectIntView(TransInfo *t, const float vec[3], int adr[2])
+{
+ projectIntViewEx(t, vec, adr, V3D_PROJ_TEST_NOP);
+}
-void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
+void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV3DProjTest flag)
{
switch (t->spacetype) {
case SPACE_VIEW3D:
{
if (t->ar->regiontype == RGN_TYPE_WINDOW) {
/* allow points behind the view [#33643] */
- if (ED_view3d_project_float_global(t->ar, vec, adr, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
+ if (ED_view3d_project_float_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
/* XXX, 2.64 and prior did this, weak! */
adr[0] = t->ar->winx / 2.0f;
adr[1] = t->ar->winy / 2.0f;
@@ -393,6 +397,10 @@ void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
zero_v2(adr);
}
+void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
+{
+ projectFloatViewEx(t, vec, adr, V3D_PROJ_TEST_NOP);
+}
void applyAspectRatio(TransInfo *t, float vec[2])
{
@@ -1543,7 +1551,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
if (ob) mul_m4_v3(ob->obmat, vecrot);
}
- projectFloatView(t, vecrot, cent); // no overflow in extreme cases
+ projectFloatViewEx(t, vecrot, cent, V3D_PROJ_TEST_CLIP_ZERO);
glPushMatrix();
@@ -5285,6 +5293,7 @@ static int createEdgeSlideVerts(TransInfo *t)
TransDataEdgeSlideVert *sv;
/* XXX, 'sv' will initialize multiple times, this is suspicious. see [#34024] */
+ BLI_assert(BLI_smallhash_haskey(&table, (uintptr_t)v) != false);
sv = sv_array + GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
sv->v = v;
sv->origvert = *v;
@@ -5307,6 +5316,7 @@ static int createEdgeSlideVerts(TransInfo *t)
e1 = e;
e = get_other_edge(v, e);
if (!e) {
+ BLI_assert(BLI_smallhash_haskey(&table, (uintptr_t)v) != false);
sv = sv_array + GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
sv->v = v;
sv->origvert = *v;
@@ -5331,6 +5341,12 @@ static int createEdgeSlideVerts(TransInfo *t)
l1 = get_next_loop(v, l1, e1, e, vec);
l2 = l2 ? get_next_loop(v, l2, e1, e, vec2) : NULL;
+ if (UNLIKELY(l1 == NULL && l2 != NULL)) {
+ l1 = l2;
+ l2 = NULL;
+ swap_v3_v3(vec, vec2);
+ }
+
BM_elem_flag_disable(v, BM_ELEM_TAG);
BM_elem_flag_disable(v2, BM_ELEM_TAG);
} while (e != v_first->e && l1);
@@ -5372,6 +5388,7 @@ static int createEdgeSlideVerts(TransInfo *t)
continue;
}
+ BLI_assert(BLI_smallhash_haskey(&table, (uintptr_t)v) != false);
j = GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
if (sv_array[j].down) {
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 9c57c74a26d..dbf56f658ac 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -35,6 +35,7 @@
#include "ED_transform.h"
#include "ED_numinput.h"
+#include "ED_view3d.h"
#include "DNA_listBase.h"
@@ -481,7 +482,9 @@ int transformEnd(struct bContext *C, TransInfo *t);
void setTransformViewMatrices(TransInfo *t);
void convertViewVec(TransInfo *t, float r_vec[3], int dx, int 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);
void projectFloatView(TransInfo *t, const float vec[3], float adr[2]);
void applyAspectRatio(TransInfo *t, float *vec);
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 5be06188e4e..57816e7546c 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -4560,7 +4560,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
short constinv;
short skip_invert = 0;
- if (ob->rigidbody_object) {
+ if (t->mode != TFM_DUMMY && ob->rigidbody_object) {
float rot[3][3], scale[3];
/* save original object transform */
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index cd6035a232b..54fb567b8a2 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -841,37 +841,89 @@ static void manipulator_setcolor(View3D *v3d, char axis, int colcode, unsigned c
glColor4ubv(col);
}
-/* viewmatrix should have been set OK, also no shademode! */
-static void draw_manipulator_axes(View3D *v3d, RegionView3D *rv3d, int colcode, int flagx, int flagy, int flagz)
+static void axis_sort_v3(const float axis_values[3], int r_axis_order[3])
{
+ float v[3];
+ copy_v3_v3(v, axis_values);
- /* axes */
- if (flagx) {
- manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
- if (flagx & MAN_SCALE_X) glLoadName(MAN_SCALE_X);
- else if (flagx & MAN_TRANS_X) glLoadName(MAN_TRANS_X);
- glBegin(GL_LINES);
- glVertex3f(0.2f, 0.0f, 0.0f);
- glVertex3f(1.0f, 0.0f, 0.0f);
- glEnd();
+#define SWAP_AXIS(a, b) { \
+ SWAP(float, v[a], v[b]); \
+ SWAP(int, r_axis_order[a], r_axis_order[b]); \
+} (void)0
+
+ if (v[0] < v[1]) {
+ if (v[2] < v[0]) { SWAP_AXIS(0, 2); }
+ }
+ else {
+ if (v[1] < v[2]) { SWAP_AXIS(0, 1); }
+ else { SWAP_AXIS(0, 2); }
}
- if (flagy) {
- if (flagy & MAN_SCALE_Y) glLoadName(MAN_SCALE_Y);
- else if (flagy & MAN_TRANS_Y) glLoadName(MAN_TRANS_Y);
- manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
- glBegin(GL_LINES);
- glVertex3f(0.0f, 0.2f, 0.0f);
- glVertex3f(0.0f, 1.0f, 0.0f);
- glEnd();
+ if (v[2] < v[1]) { SWAP_AXIS(1, 2); }
+
+#undef SWAP_AXIS
+}
+static void manipulator_axis_order(RegionView3D *rv3d, int r_axis_order[3])
+{
+ float axis_values[3];
+ float vec[3];
+
+ ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], vec);
+
+ axis_values[0] = -dot_v3v3(rv3d->twmat[0], vec);
+ axis_values[1] = -dot_v3v3(rv3d->twmat[1], vec);
+ axis_values[2] = -dot_v3v3(rv3d->twmat[2], vec);
+
+ axis_sort_v3(axis_values, r_axis_order);
+}
+
+/* viewmatrix should have been set OK, also no shademode! */
+static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int colcode,
+ int flagx, int flagy, int flagz, int axis)
+{
+ switch (axis) {
+ case 0:
+ /* axes */
+ if (flagx) {
+ manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
+ if (flagx & MAN_SCALE_X) glLoadName(MAN_SCALE_X);
+ else if (flagx & MAN_TRANS_X) glLoadName(MAN_TRANS_X);
+ glBegin(GL_LINES);
+ glVertex3f(0.2f, 0.0f, 0.0f);
+ glVertex3f(1.0f, 0.0f, 0.0f);
+ glEnd();
+ }
+ break;
+ case 1:
+ if (flagy) {
+ if (flagy & MAN_SCALE_Y) glLoadName(MAN_SCALE_Y);
+ else if (flagy & MAN_TRANS_Y) glLoadName(MAN_TRANS_Y);
+ manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
+ glBegin(GL_LINES);
+ glVertex3f(0.0f, 0.2f, 0.0f);
+ glVertex3f(0.0f, 1.0f, 0.0f);
+ glEnd();
+ }
+ break;
+ case 2:
+ if (flagz) {
+ if (flagz & MAN_SCALE_Z) glLoadName(MAN_SCALE_Z);
+ else if (flagz & MAN_TRANS_Z) glLoadName(MAN_TRANS_Z);
+ manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
+ glBegin(GL_LINES);
+ glVertex3f(0.0f, 0.0f, 0.2f);
+ glVertex3f(0.0f, 0.0f, 1.0f);
+ glEnd();
+ }
+ break;
}
- if (flagz) {
- if (flagz & MAN_SCALE_Z) glLoadName(MAN_SCALE_Z);
- else if (flagz & MAN_TRANS_Z) glLoadName(MAN_TRANS_Z);
- manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
- glBegin(GL_LINES);
- glVertex3f(0.0f, 0.0f, 0.2f);
- glVertex3f(0.0f, 0.0f, 1.0f);
- glEnd();
+}
+static void draw_manipulator_axes(View3D *v3d, RegionView3D *rv3d, int colcode,
+ int flagx, int flagy, int flagz,
+ const int axis_order[3])
+{
+ int i;
+ for (i = 0; i < 3; i++) {
+ draw_manipulator_axes_single(v3d, rv3d, colcode, flagx, flagy, flagz, axis_order[i]);
}
}
@@ -1214,10 +1266,14 @@ static void draw_manipulator_scale(View3D *v3d, RegionView3D *rv3d, int moving,
{
float cywid = 0.25f * 0.01f * (float)U.tw_handlesize;
float cusize = cywid * 0.75f, dz;
+ int axis_order[3] = {2, 0, 1};
+ int i;
/* when called while moving in mixed mode, do not draw when... */
if ((drawflags & MAN_SCALE_C) == 0) return;
+ manipulator_axis_order(rv3d, axis_order);
+
glDisable(GL_DEPTH_TEST);
/* not in combo mode */
@@ -1255,28 +1311,41 @@ static void draw_manipulator_scale(View3D *v3d, RegionView3D *rv3d, int moving,
/* axis */
/* in combo mode, this is always drawn as first type */
- draw_manipulator_axes(v3d, rv3d, colcode, drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z);
-
- /* Z cube */
- glTranslatef(0.0, 0.0, dz);
- if (drawflags & MAN_SCALE_Z) {
- if (G.f & G_PICKSEL) glLoadName(MAN_SCALE_Z);
- manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
- drawsolidcube(cusize);
- }
- /* X cube */
- glTranslatef(dz, 0.0, -dz);
- if (drawflags & MAN_SCALE_X) {
- if (G.f & G_PICKSEL) glLoadName(MAN_SCALE_X);
- manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
- drawsolidcube(cusize);
- }
- /* Y cube */
- glTranslatef(-dz, dz, 0.0);
- if (drawflags & MAN_SCALE_Y) {
- if (G.f & G_PICKSEL) glLoadName(MAN_SCALE_Y);
- manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
- drawsolidcube(cusize);
+ draw_manipulator_axes(v3d, rv3d, colcode,
+ drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z,
+ axis_order);
+
+
+ for (i = 0; i < 3; i++) {
+ switch (axis_order[i]) {
+ case 0: /* X cube */
+ if (drawflags & MAN_SCALE_X) {
+ glTranslatef(dz, 0.0, 0.0);
+ if (G.f & G_PICKSEL) glLoadName(MAN_SCALE_X);
+ manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
+ drawsolidcube(cusize);
+ glTranslatef(-dz, 0.0, 0.0);
+ }
+ break;
+ case 1: /* Y cube */
+ if (drawflags & MAN_SCALE_Y) {
+ glTranslatef(0.0, dz, 0.0);
+ if (G.f & G_PICKSEL) glLoadName(MAN_SCALE_Y);
+ manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
+ drawsolidcube(cusize);
+ glTranslatef(0.0, -dz, 0.0);
+ }
+ break;
+ case 2: /* Z cube */
+ if (drawflags & MAN_SCALE_Z) {
+ glTranslatef(0.0, 0.0, dz);
+ if (G.f & G_PICKSEL) glLoadName(MAN_SCALE_Z);
+ manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
+ drawsolidcube(cusize);
+ glTranslatef(0.0, 0.0, -dz);
+ }
+ break;
+ }
}
/* if shiftkey, center point as last, for selectbuffer order */
@@ -1333,16 +1402,17 @@ static void draw_manipulator_translate(View3D *v3d, RegionView3D *rv3d, int UNUS
float cywid = 0.25f * cylen, dz, size;
float unitmat[4][4];
int shift = 0; // XXX
+ int axis_order[3] = {0, 1, 2};
+ int i;
/* when called while moving in mixed mode, do not draw when... */
if ((drawflags & MAN_TRANS_C) == 0) return;
+ manipulator_axis_order(rv3d, axis_order);
+
// XXX if (moving) glTranslatef(t->vec[0], t->vec[1], t->vec[2]);
glDisable(GL_DEPTH_TEST);
- qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_FILL);
-
/* center circle, do not add to selection when shift is pressed (planar constraint) */
if ((G.f & G_PICKSEL) && shift == 0) glLoadName(MAN_TRANS_C);
@@ -1360,8 +1430,11 @@ static void draw_manipulator_translate(View3D *v3d, RegionView3D *rv3d, int UNUS
glLoadName(-1);
// translate drawn as last, only axis when no combo with scale, or for ghosting
- if ((combo & V3D_MANIP_SCALE) == 0 || colcode == MAN_GHOST)
- draw_manipulator_axes(v3d, rv3d, colcode, drawflags & MAN_TRANS_X, drawflags & MAN_TRANS_Y, drawflags & MAN_TRANS_Z);
+ if ((combo & V3D_MANIP_SCALE) == 0 || colcode == MAN_GHOST) {
+ draw_manipulator_axes(v3d, rv3d, colcode,
+ drawflags & MAN_TRANS_X, drawflags & MAN_TRANS_Y, drawflags & MAN_TRANS_Z,
+ axis_order);
+ }
/* offset in combo mode, for rotate a bit more */
@@ -1369,29 +1442,43 @@ static void draw_manipulator_translate(View3D *v3d, RegionView3D *rv3d, int UNUS
else if (combo & (V3D_MANIP_SCALE)) dz = 1.0f + 0.5f * cylen;
else dz = 1.0f;
- /* Z Cone */
- glTranslatef(0.0, 0.0, dz);
- if (drawflags & MAN_TRANS_Z) {
- if (G.f & G_PICKSEL) glLoadName(MAN_TRANS_Z);
- manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
- draw_cone(qobj, cylen, cywid);
- }
- /* X Cone */
- glTranslatef(dz, 0.0, -dz);
- if (drawflags & MAN_TRANS_X) {
- if (G.f & G_PICKSEL) glLoadName(MAN_TRANS_X);
- glRotatef(90.0, 0.0, 1.0, 0.0);
- manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
- draw_cone(qobj, cylen, cywid);
- glRotatef(-90.0, 0.0, 1.0, 0.0);
- }
- /* Y Cone */
- glTranslatef(-dz, dz, 0.0);
- if (drawflags & MAN_TRANS_Y) {
- if (G.f & G_PICKSEL) glLoadName(MAN_TRANS_Y);
- glRotatef(-90.0, 1.0, 0.0, 0.0);
- manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
- draw_cone(qobj, cylen, cywid);
+ qobj = gluNewQuadric();
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+
+ for (i = 0; i < 3; i++) {
+ switch (axis_order[i]) {
+ case 0: /* Z Cone */
+ if (drawflags & MAN_TRANS_Z) {
+ glTranslatef(0.0, 0.0, dz);
+ if (G.f & G_PICKSEL) glLoadName(MAN_TRANS_Z);
+ manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
+ draw_cone(qobj, cylen, cywid);
+ glTranslatef(0.0, 0.0, -dz);
+ }
+ break;
+ case 1: /* X Cone */
+ if (drawflags & MAN_TRANS_X) {
+ glTranslatef(dz, 0.0, 0.0);
+ if (G.f & G_PICKSEL) glLoadName(MAN_TRANS_X);
+ glRotatef(90.0, 0.0, 1.0, 0.0);
+ manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
+ draw_cone(qobj, cylen, cywid);
+ glRotatef(-90.0, 0.0, 1.0, 0.0);
+ glTranslatef(-dz, 0.0, 0.0);
+ }
+ break;
+ case 2: /* Y Cone */
+ if (drawflags & MAN_TRANS_Y) {
+ glTranslatef(0.0, dz, 0.0);
+ if (G.f & G_PICKSEL) glLoadName(MAN_TRANS_Y);
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
+ draw_cone(qobj, cylen, cywid);
+ glRotatef(90.0, 1.0, 0.0, 0.0);
+ glTranslatef(0.0, -dz, 0.0);
+ }
+ break;
+ }
}
gluDeleteQuadric(qobj);
@@ -1407,10 +1494,13 @@ static void draw_manipulator_rotate_cyl(View3D *v3d, RegionView3D *rv3d, int mov
float size;
float cylen = 0.01f * (float)U.tw_handlesize;
float cywid = 0.25f * cylen;
-
+ int axis_order[3] = {2, 0, 1};
+ int i;
/* when called while moving in mixed mode, do not draw when... */
if ((drawflags & MAN_ROT_C) == 0) return;
+ manipulator_axis_order(rv3d, axis_order);
+
/* prepare for screen aligned draw */
glPushMatrix();
size = screen_aligned(rv3d, rv3d->twmat);
@@ -1461,36 +1551,50 @@ static void draw_manipulator_rotate_cyl(View3D *v3d, RegionView3D *rv3d, int mov
if ((G.f & G_PICKSEL) == 0) {
// only draw axis when combo didn't draw scale axes
- if ((combo & V3D_MANIP_SCALE) == 0)
- draw_manipulator_axes(v3d, rv3d, colcode, drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z);
+ if ((combo & V3D_MANIP_SCALE) == 0) {
+ draw_manipulator_axes(v3d, rv3d, colcode,
+ drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z,
+ axis_order);
+ }
/* only has to be set when not in picking */
gluQuadricDrawStyle(qobj, GLU_FILL);
}
- /* Z cyl */
- glTranslatef(0.0, 0.0, 1.0);
- if (drawflags & MAN_ROT_Z) {
- if (G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
- manipulator_setcolor(v3d, 'Z', colcode, 255);
- draw_cylinder(qobj, cylen, cywid);
- }
- /* X cyl */
- glTranslatef(1.0, 0.0, -1.0);
- if (drawflags & MAN_ROT_X) {
- if (G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
- glRotatef(90.0, 0.0, 1.0, 0.0);
- manipulator_setcolor(v3d, 'X', colcode, 255);
- draw_cylinder(qobj, cylen, cywid);
- glRotatef(-90.0, 0.0, 1.0, 0.0);
- }
- /* Y cylinder */
- glTranslatef(-1.0, 1.0, 0.0);
- if (drawflags & MAN_ROT_Y) {
- if (G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
- glRotatef(-90.0, 1.0, 0.0, 0.0);
- manipulator_setcolor(v3d, 'Y', colcode, 255);
- draw_cylinder(qobj, cylen, cywid);
+ for (i = 0; i < 3; i++) {
+ switch (axis_order[i]) {
+ case 0: /* X cylinder */
+ if (drawflags & MAN_ROT_X) {
+ glTranslatef(1.0, 0.0, 0.0);
+ if (G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
+ glRotatef(90.0, 0.0, 1.0, 0.0);
+ manipulator_setcolor(v3d, 'X', colcode, 255);
+ draw_cylinder(qobj, cylen, cywid);
+ glRotatef(-90.0, 0.0, 1.0, 0.0);
+ glTranslatef(-1.0, 0.0, 0.0);
+ }
+ break;
+ case 1: /* Y cylinder */
+ if (drawflags & MAN_ROT_Y) {
+ glTranslatef(0.0, 1.0, 0.0);
+ if (G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ manipulator_setcolor(v3d, 'Y', colcode, 255);
+ draw_cylinder(qobj, cylen, cywid);
+ glRotatef(90.0, 1.0, 0.0, 0.0);
+ glTranslatef(0.0, -1.0, 0.0);
+ }
+ break;
+ case 2: /* Z cylinder */
+ if (drawflags & MAN_ROT_Z) {
+ glTranslatef(0.0, 0.0, 1.0);
+ if (G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
+ manipulator_setcolor(v3d, 'Z', colcode, 255);
+ draw_cylinder(qobj, cylen, cywid);
+ glTranslatef(0.0, 0.0, -1.0);
+ }
+ break;
+ }
}
/* restore */
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 32dc31954f2..0392c0f47a2 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -37,6 +37,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_armature.h"
@@ -169,7 +171,7 @@ static int select_orientation_invoke(bContext *C, wmOperator *UNUSED(op), wmEven
uiPopupMenu *pup;
uiLayout *layout;
- pup = uiPupMenuBegin(C, "Orientation", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Orientation"), ICON_NONE);
layout = uiPupMenuLayout(pup);
uiItemsEnumO(layout, "TRANSFORM_OT_select_orientation", "orientation");
uiPupMenuEnd(C, pup);
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 23d6b0a075e..f0f31b1e793 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -42,6 +42,8 @@
#include "BLI_blenlib.h"
+#include "BLF_translation.h"
+
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
@@ -174,10 +176,10 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha
char line[FILE_MAX + 100];
wmOperatorType *ot = WM_operatortype_find(opname, 1);
- pup = uiPupMenuBegin(C, "Unpack file", ICON_NONE);
+ pup = uiPupMenuBegin(C, IFACE_("Unpack File"), ICON_NONE);
layout = uiPupMenuLayout(pup);
- strcpy(line, "Remove Pack");
+ strcpy(line, IFACE_("Remove Pack"));
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_REMOVE);
RNA_string_set(&props_ptr, "id", id_name);
@@ -191,14 +193,14 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha
if (strcmp(abs_name, local_name) != 0) {
switch (checkPackedFile(local_name, pf)) {
case PF_NOFILE:
- BLI_snprintf(line, sizeof(line), "Create %s", local_name);
+ BLI_snprintf(line, sizeof(line), IFACE_("Create %s"), local_name);
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL);
RNA_string_set(&props_ptr, "id", id_name);
break;
case PF_EQUAL:
- BLI_snprintf(line, sizeof(line), "Use %s (identical)", local_name);
+ BLI_snprintf(line, sizeof(line), IFACE_("Use %s (identical)"), local_name);
//uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_LOCAL);
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_USE_LOCAL);
@@ -206,13 +208,13 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha
break;
case PF_DIFFERS:
- BLI_snprintf(line, sizeof(line), "Use %s (differs)", local_name);
+ BLI_snprintf(line, sizeof(line), IFACE_("Use %s (differs)"), local_name);
//uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_LOCAL);
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_USE_LOCAL);
RNA_string_set(&props_ptr, "id", id_name);
- BLI_snprintf(line, sizeof(line), "Overwrite %s", local_name);
+ BLI_snprintf(line, sizeof(line), IFACE_("Overwrite %s"), local_name);
//uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_LOCAL);
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL);
@@ -224,27 +226,27 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha
switch (checkPackedFile(abs_name, pf)) {
case PF_NOFILE:
- BLI_snprintf(line, sizeof(line), "Create %s", abs_name);
+ BLI_snprintf(line, sizeof(line), IFACE_("Create %s"), abs_name);
//uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_ORIGINAL);
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL);
RNA_string_set(&props_ptr, "id", id_name);
break;
case PF_EQUAL:
- BLI_snprintf(line, sizeof(line), "Use %s (identical)", abs_name);
+ BLI_snprintf(line, sizeof(line), IFACE_("Use %s (identical)"), abs_name);
//uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_ORIGINAL);
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL);
RNA_string_set(&props_ptr, "id", id_name);
break;
case PF_DIFFERS:
- BLI_snprintf(line, sizeof(line), "Use %s (differs)", abs_name);
+ BLI_snprintf(line, sizeof(line), IFACE_("Use %s (differs)"), abs_name);
//uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_ORIGINAL);
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL);
RNA_string_set(&props_ptr, "id", id_name);
- BLI_snprintf(line, sizeof(line), "Overwrite %s", abs_name);
+ BLI_snprintf(line, sizeof(line), IFACE_("Overwrite %s"), abs_name);
//uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_ORIGINAL);
props_ptr = uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL);
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index 8a0ef06ef12..ac2ee21d09d 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -83,8 +83,8 @@ void ED_undo_push(bContext *C, const char *str)
Object *obact = CTX_data_active_object(C);
if (G.debug & G_DEBUG)
- printf("undo push %s\n", str);
-
+ printf("%s: %s\n", __func__, str);
+
if (obedit) {
if (U.undosteps == 0) return;
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index a17d3c20c1c..fbb6250c05b 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -113,7 +113,7 @@ static int ED_operator_uvedit_can_uv_sculpt(struct bContext *C)
return ED_space_image_show_uvedit(sima, obedit) && !(toolsettings->use_uv_sculpt);
}
-static int UNUSED_FUNCTION(ED_operator_uvmap_mesh) (bContext * C)
+static int UNUSED_FUNCTION(ED_operator_uvmap_mesh) (bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -1582,7 +1582,7 @@ static void UV_OT_align(wmOperatorType *ot)
/* api callbacks */
ot->exec = align_exec;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
/* properties */
RNA_def_enum(ot->srna, "axis", axis_items, 'a', "Axis", "Axis to align UV locations on");
@@ -2258,7 +2258,7 @@ static void UV_OT_select(wmOperatorType *ot)
/* api callbacks */
ot->exec = select_exec;
ot->invoke = select_invoke;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
/* properties */
RNA_def_boolean(ot->srna, "extend", 0,
@@ -2303,7 +2303,7 @@ static void UV_OT_select_loop(wmOperatorType *ot)
/* api callbacks */
ot->exec = select_loop_exec;
ot->invoke = select_loop_invoke;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
/* properties */
RNA_def_boolean(ot->srna, "extend", 0,
@@ -2377,7 +2377,7 @@ static void UV_OT_select_linked(wmOperatorType *ot)
/* api callbacks */
ot->exec = select_linked_exec;
- ot->poll = ED_operator_image_active; /* requires space image */
+ ot->poll = ED_operator_uvedit; /* requires space image */
/* properties */
RNA_def_boolean(ot->srna, "extend", 0,
@@ -2405,7 +2405,7 @@ static void UV_OT_select_linked_pick(wmOperatorType *ot)
/* api callbacks */
ot->invoke = select_linked_pick_invoke;
ot->exec = select_linked_pick_exec;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
/* properties */
RNA_def_boolean(ot->srna, "extend", 0,
@@ -2842,7 +2842,7 @@ static void UV_OT_select_border(wmOperatorType *ot)
ot->invoke = WM_border_select_invoke;
ot->exec = border_select_exec;
ot->modal = WM_border_select_modal;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
ot->cancel = WM_border_select_cancel;
/* flags */
@@ -2966,7 +2966,7 @@ static void UV_OT_circle_select(wmOperatorType *ot)
ot->invoke = WM_gesture_circle_invoke;
ot->modal = WM_gesture_circle_modal;
ot->exec = circle_select_exec;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
ot->cancel = WM_gesture_circle_cancel;
/* flags */
@@ -3095,7 +3095,7 @@ static void UV_OT_select_lasso(wmOperatorType *ot)
ot->invoke = WM_gesture_lasso_invoke;
ot->modal = WM_gesture_lasso_modal;
ot->exec = uv_lasso_select_exec;
- ot->poll = ED_operator_image_active;
+ ot->poll = ED_operator_uvedit;
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
@@ -3170,7 +3170,7 @@ static void UV_OT_snap_cursor(wmOperatorType *ot)
/* api callbacks */
ot->exec = snap_cursor_exec;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
/* properties */
RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
@@ -3350,7 +3350,7 @@ static void UV_OT_snap_selected(wmOperatorType *ot)
/* api callbacks */
ot->exec = snap_selection_exec;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
/* properties */
RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
@@ -3769,7 +3769,7 @@ static void UV_OT_cursor_set(wmOperatorType *ot)
/* api callbacks */
ot->exec = set_2d_cursor_exec;
ot->invoke = set_2d_cursor_invoke;
- ot->poll = ED_operator_image_active; /* requires space image */;
+ ot->poll = ED_operator_uvedit; /* requires space image */;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 6abc41759e7..faeb0f721f4 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -50,6 +50,7 @@ set(SRC
intern/gpu_codegen.c
intern/gpu_draw.c
intern/gpu_extensions.c
+ intern/gpu_fixed_material.c
intern/gpu_material.c
GPU_buffers.h
@@ -59,10 +60,12 @@ set(SRC
intern/gpu_codegen.h
)
+data_to_c_simple(shaders/gpu_shader_fixed_fragment.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_fixed_vertex.glsl SRC)
data_to_c_simple(shaders/gpu_shader_material.glsl SRC)
-data_to_c_simple(shaders/gpu_shader_vertex.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_vertex.glsl SRC)
data_to_c_simple(shaders/gpu_shader_vsm_store_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_vsm_store_vert.glsl SRC)
diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h
index 66a7c917a55..7492304bd40 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -32,6 +32,8 @@
#ifndef __GPU_EXTENSIONS_H__
#define __GPU_EXTENSIONS_H__
+#include "BLI_utildefines.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -160,17 +162,17 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels);
* - 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 *libcode); /*GPUShader *lib);*/
-/*GPUShader *GPU_shader_create_lib(const char *code);*/
+GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *libcode, const char *defines);
void GPU_shader_free(GPUShader *shader);
void GPU_shader_bind(GPUShader *shader);
-void GPU_shader_unbind(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, float *value);
void GPU_shader_uniform_texture(GPUShader *shader, int location, GPUTexture *tex);
+void GPU_shader_uniform_int(GPUShader *shader, int location, int value);
int GPU_shader_get_attribute(GPUShader *shader, const char *name);
@@ -199,6 +201,30 @@ typedef struct GPUVertexAttribs {
int totlayer;
} GPUVertexAttribs;
+/* Fixed Function Materials */
+
+typedef enum GPUFixedMaterialOption {
+ GPU_FIXED_COLOR_MATERIAL = (1<<0), /* replace diffuse with glcolor */
+ GPU_FIXED_SOLID_LIGHTING = (1<<1), /* use solid lighting (only 3 directional lights) */
+ GPU_FIXED_SCENE_LIGHTING = (1<<2), /* use scene lighting (up to 8 arbitrary lights) */
+ GPU_FIXED_TWO_SIDED = (1<<3), /* flip normals towards viewer */
+ GPU_FIXED_TEXTURE_2D = (1<<4), /* use 2D texture to replace diffuse color */
+
+ GPU_FIXED_OPTIONS_NUM = 5,
+ GPU_FIXED_OPTION_COMBINATIONS = (1<<GPU_FIXED_OPTIONS_NUM)
+} GPUFixedMaterialOption;
+
+void GPU_fixed_materials_init(void);
+void GPU_fixed_materials_exit(void);
+
+void GPU_fixed_material_shader_bind(int options);
+void GPU_fixed_material_shader_unbind(void);
+
+void GPU_fixed_material_colors(const float diffuse[3], const float specular[3],
+ int shininess, float alpha);
+
+bool GPU_fixed_material_need_normals(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript
index f7db3dfeaa0..ccea40c0909 100644
--- a/source/blender/gpu/SConscript
+++ b/source/blender/gpu/SConscript
@@ -49,10 +49,12 @@ if env['WITH_BF_DDS']:
# generated data files
import os
sources.extend((
+ os.path.join(env['DATA_SOURCES'], "gpu_shader_fixed_fragment.glsl.c"),
+ os.path.join(env['DATA_SOURCES'], "gpu_shader_fixed_vertex.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_material.glsl.c"),
- os.path.join(env['DATA_SOURCES'], "gpu_shader_vertex.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_vsm_store_frag.glsl.c"),
os.path.join(env['DATA_SOURCES'], "gpu_shader_vsm_store_vert.glsl.c"),
))
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index b27a4be9f21..59953659a2c 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -237,8 +237,6 @@ GPUFunction *GPU_lookup_function(const char *name)
if (!FUNCTION_HASH) {
FUNCTION_HASH = BLI_ghash_str_new("GPU_lookup_function gh");
gpu_parse_functions_string(FUNCTION_HASH, glsl_material_library);
- /*FUNCTION_PROTOTYPES = gpu_generate_function_prototyps(FUNCTION_HASH);
- FUNCTION_LIB = GPU_shader_create_lib(datatoc_gpu_shader_material_glsl);*/
}
return (GPUFunction*)BLI_ghash_lookup(FUNCTION_HASH, (void *)name);
@@ -758,7 +756,7 @@ static void GPU_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
}
}
- GPU_shader_unbind(shader);
+ GPU_shader_unbind();
}
void GPU_pass_bind(GPUPass *pass, double time, int mipmap)
@@ -820,7 +818,7 @@ void GPU_pass_unbind(GPUPass *pass)
input->tex = NULL;
}
- GPU_shader_unbind(shader);
+ GPU_shader_unbind();
}
/* Node Link Functions */
@@ -1368,7 +1366,7 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttri
/* generate code and compile with opengl */
fragmentcode = code_generate_fragment(nodes, outlink->output, name);
vertexcode = code_generate_vertex(nodes);
- shader = GPU_shader_create(vertexcode, fragmentcode, glsl_material_library); /*FUNCTION_LIB);*/
+ shader = GPU_shader_create(vertexcode, fragmentcode, glsl_material_library, NULL);
/* failed? */
if (!shader) {
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index e8e47013159..56aa4b222cb 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -205,12 +205,15 @@ void GPU_extensions_init(void)
#else
GG.os = GPU_OS_UNIX;
#endif
+
+ GPU_fixed_materials_init();
}
void GPU_extensions_exit(void)
{
gpu_extensions_init = 0;
GPU_codegen_exit();
+ GPU_fixed_materials_exit();
}
int GPU_glsl_support(void)
@@ -1006,7 +1009,7 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b
glTexCoord2d(0, 1); glVertex2f(1, -1);
glEnd();
- GPU_shader_unbind(blur_shader);
+ GPU_shader_unbind();
}
/* GPUOffScreen */
@@ -1124,13 +1127,11 @@ static void shader_print_errors(const char *task, char *log, const char *code)
fprintf(stderr, "%s\n", log);
}
-GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, /*GPUShader *lib,*/ const char *libcode)
+GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *libcode, const char *defines)
{
GLint status;
GLcharARB log[5000];
- const char *fragsource[2];
GLsizei length = 0;
- GLint count;
GPUShader *shader;
if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
@@ -1154,8 +1155,14 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, /*GPU
}
if (vertexcode) {
+ const char *source[2];
+ int num_source = 0;
+
+ if (defines) source[num_source++] = defines;
+ if (vertexcode) source[num_source++] = vertexcode;
+
glAttachObjectARB(shader->object, shader->vertex);
- glShaderSourceARB(shader->vertex, 1, (const char**)&vertexcode, NULL);
+ glShaderSourceARB(shader->vertex, num_source, source, NULL);
glCompileShaderARB(shader->vertex);
glGetObjectParameterivARB(shader->vertex, GL_OBJECT_COMPILE_STATUS_ARB, &status);
@@ -1170,12 +1177,15 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, /*GPU
}
if (fragcode) {
- count = 0;
- if (libcode) fragsource[count++] = libcode;
- if (fragcode) fragsource[count++] = fragcode;
+ const char *source[3];
+ int num_source = 0;
+
+ if (defines) source[num_source++] = defines;
+ if (libcode) source[num_source++] = libcode;
+ if (fragcode) source[num_source++] = fragcode;
glAttachObjectARB(shader->object, shader->fragment);
- glShaderSourceARB(shader->fragment, count, fragsource, NULL);
+ glShaderSourceARB(shader->fragment, num_source, source, NULL);
glCompileShaderARB(shader->fragment);
glGetObjectParameterivARB(shader->fragment, GL_OBJECT_COMPILE_STATUS_ARB, &status);
@@ -1254,7 +1264,7 @@ void GPU_shader_bind(GPUShader *shader)
GPU_print_error("Post Shader Bind");
}
-void GPU_shader_unbind(GPUShader *UNUSED(shader))
+void GPU_shader_unbind()
{
GPU_print_error("Pre Shader Unbind");
glUseProgramObjectARB(0);
@@ -1296,6 +1306,16 @@ void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int leng
GPU_print_error("Post Uniform Vector");
}
+void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value)
+{
+ if (location == -1)
+ return;
+
+ GPU_print_error("Pre Uniform Int");
+ glUniform1iARB(location, value);
+ GPU_print_error("Post Uniform Int");
+}
+
void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex)
{
GLenum arbnumber;
@@ -1344,12 +1364,12 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
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);
+ GG.shaders.vsm_store = GPU_shader_create(datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, NULL, NULL);
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);
+ 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);
retval = GG.shaders.sep_gaussian_blur;
break;
}
diff --git a/source/blender/gpu/intern/gpu_fixed_material.c b/source/blender/gpu/intern/gpu_fixed_material.c
new file mode 100644
index 00000000000..d5a04c88e89
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_fixed_material.c
@@ -0,0 +1,191 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public 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_fixed_material.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 "GL/glew.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+
+#include "GPU_extensions.h"
+
+/* Fixed function material types */
+
+static struct {
+ GPUShader *cached_shaders[GPU_FIXED_OPTION_COMBINATIONS];
+ bool failed_shaders[GPU_FIXED_OPTION_COMBINATIONS];
+
+ bool need_normals;
+} GPU_MATERIAL_STATE;
+
+/* Init / exit */
+
+void GPU_fixed_materials_init()
+{
+ memset(&GPU_MATERIAL_STATE, 0, sizeof(GPU_MATERIAL_STATE));
+}
+
+void GPU_fixed_materials_exit()
+{
+ int i;
+
+ for (i = 0; i < GPU_FIXED_OPTION_COMBINATIONS; i++)
+ if (GPU_MATERIAL_STATE.cached_shaders[i])
+ GPU_shader_free(GPU_MATERIAL_STATE.cached_shaders[i]);
+}
+
+/* Shader lookup / create */
+
+static GPUShader *gpu_fixed_material_shader(int options)
+{
+ /* glsl code */
+ extern char datatoc_gpu_shader_fixed_vertex_glsl[];
+ extern char datatoc_gpu_shader_fixed_fragment_glsl[];
+
+ /* cached shaders */
+ GPUShader *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_FIXED_OPTIONS_NUM] = "";
+
+ if (options & GPU_FIXED_COLOR_MATERIAL)
+ strcat(defines, "#define USE_COLOR\n");
+ if (options & GPU_FIXED_TWO_SIDED)
+ strcat(defines, "#define USE_TWO_SIDED\n");
+ if (options & GPU_FIXED_SOLID_LIGHTING)
+ strcat(defines, "#define USE_SOLID_LIGHTING\n");
+ if (options & GPU_FIXED_SCENE_LIGHTING)
+ strcat(defines, "#define USE_SCENE_LIGHTING\n");
+ if (options & GPU_FIXED_TEXTURE_2D)
+ strcat(defines, "#define USE_TEXTURE\n");
+
+ shader = GPU_shader_create(
+ datatoc_gpu_shader_fixed_vertex_glsl,
+ datatoc_gpu_shader_fixed_fragment_glsl,
+ NULL, defines);
+
+ if (shader) {
+ /* set texture map to first texture unit */
+ if (options & GPU_FIXED_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_fixed_material_shader_bind(int options)
+{
+ if (GPU_glsl_support()) {
+ GPUShader *shader = gpu_fixed_material_shader(options);
+
+ if (shader)
+ GPU_shader_bind(shader);
+ }
+ else {
+ if (options & (GPU_FIXED_SOLID_LIGHTING|GPU_FIXED_SCENE_LIGHTING))
+ glEnable(GL_LIGHTING);
+
+ if (options & GPU_FIXED_TWO_SIDED)
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
+
+ if (options & GPU_FIXED_COLOR_MATERIAL) {
+ glEnable(GL_COLOR_MATERIAL);
+ glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+ }
+
+ if (options & GPU_FIXED_TEXTURE_2D)
+ glEnable(GL_TEXTURE_2D);
+ }
+
+ /* temporary hack, should be solved outside of this file */
+ GPU_MATERIAL_STATE.need_normals = (options & (GPU_FIXED_SOLID_LIGHTING|GPU_FIXED_SCENE_LIGHTING));
+}
+
+void GPU_fixed_material_shader_unbind()
+{
+ 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_fixed_material_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, diffuse);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
+ glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, CLAMPIS(shininess, 1, 128));
+}
+
+bool GPU_fixed_material_need_normals()
+{
+ return GPU_MATERIAL_STATE.need_normals;
+}
+
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index b5ef27a338d..d7ac6febfb7 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -1919,7 +1919,7 @@ void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsiz
void GPU_lamp_shadow_buffer_unbind(GPULamp *lamp)
{
if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) {
- GPU_shader_unbind(GPU_shader_get_builtin_shader(GPU_SHADER_VSM_STORE));
+ GPU_shader_unbind();
GPU_framebuffer_blur(lamp->fb, lamp->tex, lamp->blurfb, lamp->blurtex);
}
diff --git a/source/blender/gpu/shaders/gpu_shader_fixed_fragment.glsl b/source/blender/gpu/shaders/gpu_shader_fixed_fragment.glsl
new file mode 100644
index 00000000000..9610e0cf5aa
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fixed_fragment.glsl
@@ -0,0 +1,169 @@
+
+/* 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_fixed_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_fixed_vertex.glsl
new file mode 100644
index 00000000000..612f9cff6aa
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fixed_vertex.glsl
@@ -0,0 +1,48 @@
+
+#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
+
+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 __GLSL_CG_DATA_TYPES
+ // Setting gl_ClipVertex is necessary to get glClipPlane working on NVIDIA graphic cards.
+ // gl_ClipVertex works only on NVIDIA graphic cards so we have to check with
+ // __GLSL_CG_DATA_TYPES if a NVIDIA graphic card is used (Cg support).
+ // gl_ClipVerte is supported up to GLSL 1.20.
+ gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
+#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_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
index 574455e42b3..9e0db44ed31 100644
--- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
@@ -14,7 +14,7 @@ void main()
// gl_ClipVertex works only on NVIDIA graphic cards so we have to check with
// __GLSL_CG_DATA_TYPES if a NVIDIA graphic card is used (Cg support).
// gl_ClipVerte is supported up to GLSL 1.20.
- #ifdef __GLSL_CG_DATA_TYPES
- gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
- #endif
+#ifdef __GLSL_CG_DATA_TYPES
+ gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
+#endif
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index e1ef7d92bd0..96bdb6c9bdd 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -1519,7 +1519,8 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan, f
if (!ret ||
!scene->addCache(ikscene->cache) ||
!scene->addSolver(ikscene->solver) ||
- !scene->initialize()) {
+ !scene->initialize())
+ {
delete ikscene;
ikscene = NULL;
}
@@ -1566,7 +1567,8 @@ static int init_scene(Object *ob)
if (ob->pose->ikdata) {
for (scene = ((IK_Data *)ob->pose->ikdata)->first;
scene != NULL;
- scene = scene->next) {
+ scene = scene->next)
+ {
if (fabs(scene->blScale - scale) > KDL::epsilon)
return 1;
scene->channels[0].pchan->flag |= POSE_IKTREE;
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index ff297d70cc3..cfeacff7f4a 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -1702,13 +1702,11 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, int save_as_render, int
int do_colormanagement;
int is_movie = BKE_imtype_is_movie(image_format_data->imtype);
int requires_linear_float = BKE_imtype_requires_linear_float(image_format_data->imtype);
+ int do_alpha_under = image_format_data->planes != R_IMF_PLANES_RGBA;
do_colormanagement = save_as_render && (is_movie || !requires_linear_float);
- if (do_colormanagement) {
- int make_byte = FALSE;
- ImFileType *type;
-
+ if (do_colormanagement || do_alpha_under) {
if (allocate_result) {
colormanaged_ibuf = IMB_dupImBuf(ibuf);
}
@@ -1727,6 +1725,41 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, int save_as_render, int
ibuf->mall |= IB_rectfloat;
}
}
+ }
+
+ /* If we're saving from RGBA to RGB buffer then it's not
+ * so much useful to just ignore alpha -- it leads to bad
+ * artifacts especially when saving byte images.
+ *
+ * What we do here is we're overing our image on top of
+ * background color (which is currently black).
+ *
+ * This is quite much the same as what Gimp does and it
+ * seems to be what artists expects from saving.
+ *
+ * Do a conversion here, so image format writers could
+ * happily assume all the alpha tricks were made already.
+ * helps keep things locally here, not spreading it to
+ * all possible image writers we've got.
+ */
+ if (do_alpha_under) {
+ float color[3] = {0, 0, 0};
+
+ if (colormanaged_ibuf->rect_float && colormanaged_ibuf->channels == 4) {
+ IMB_alpha_under_color_float(colormanaged_ibuf->rect_float, colormanaged_ibuf->x,
+ colormanaged_ibuf->y, color);
+ }
+
+ if (colormanaged_ibuf->rect) {
+ IMB_alpha_under_color_byte((unsigned char *)colormanaged_ibuf->rect,
+ colormanaged_ibuf->x, colormanaged_ibuf->y,
+ color);
+ }
+ }
+
+ if (do_colormanagement) {
+ int make_byte = FALSE;
+ ImFileType *type;
/* for proper check whether byte buffer is required by a format or not
* should be pretty safe since this image buffer is supposed to be used for
diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c
index 5c2dc0c7df9..37070c7e2bf 100644
--- a/source/blender/imbuf/intern/filetype.c
+++ b/source/blender/imbuf/intern/filetype.c
@@ -26,6 +26,9 @@
#include <stddef.h>
+
+#include "BLI_utildefines.h"
+
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_filetype.h"
@@ -56,7 +59,7 @@ static int imb_ftype_iris(ImFileType *type, ImBuf *ibuf)
return (ibuf->ftype == IMAGIC);
}
#ifdef WITH_QUICKTIME
-static int imb_ftype_quicktime(ImFileType *type, ImBuf *ibuf)
+static int imb_ftype_quicktime(ImFileType *UNUSED(type), ImBuf *UNUSED(ibuf))
{
return 0; /* XXX */
}
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 59282c9d207..26dd0f2977a 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -367,9 +367,9 @@ void IMB_alpha_under_color_byte(unsigned char *rect, int x, int y, float backcol
else {
int mul = 255 - cp[3];
- cp[0] += mul * backcol[0] / 255;
- cp[1] += mul * backcol[1] / 255;
- cp[2] += mul * backcol[2] / 255;
+ cp[0] = (cp[0] * cp[3] >> 8) + mul * backcol[0] / 255;
+ cp[1] = (cp[1] * cp[3] >> 8) + mul * backcol[1] / 255;
+ cp[2] = (cp[2] * cp[3] >> 8) + mul * backcol[2] / 255;
}
cp[3] = 255;
diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c
index 3d04b8ee184..f4ac4322747 100644
--- a/source/blender/imbuf/intern/jp2.c
+++ b/source/blender/imbuf/intern/jp2.c
@@ -803,7 +803,7 @@ static opj_image_t *ibuftoimage(ImBuf *ibuf, opj_cparameters_t *parameters)
case 16:
if (numcomps == 4) {
- if (channels_in_float == 4){
+ if (channels_in_float == 4) {
PIXEL_LOOPER_BEGIN(rect_float)
{
premul_to_straight_v4_v4(from_straight, rect_float);
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index 3f6e6c59137..392c92148b4 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -27,6 +27,10 @@
/** \file DNA_action_types.h
* \ingroup DNA
+ *
+ * Define actions data-block for the animation system.
+ * A collection of animation curves and drivers to be assigned to data-blocks
+ * or sequenced in the non-linear-editor (NLA).
*/
#ifndef __DNA_ACTION_TYPES_H__
@@ -692,4 +696,4 @@ typedef enum ACHAN_FLAG {
ACHAN_MOVED = (1 << 31)
} ACHAN_FLAG;
-#endif
+#endif /* __DNA_ACTION_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h
index 7c4772f24e8..1495ba1b1a5 100644
--- a/source/blender/makesdna/DNA_actuator_types.h
+++ b/source/blender/makesdna/DNA_actuator_types.h
@@ -27,6 +27,8 @@
/** \file DNA_actuator_types.h
* \ingroup DNA
+ *
+ * #bActuator type is specifically for use by Object logic-bricks in the game-engine.
*/
#ifndef __DNA_ACTUATOR_TYPES_H__
@@ -535,6 +537,4 @@ typedef struct bActuator {
#define ACT_STEERING_AUTOMATICFACING 4
#define ACT_STEERING_NORMALUP 8
-#endif
-
-
+#endif /* __DNA_ACTUATOR_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 1ac6e6db94b..73e2a9f433b 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -284,15 +284,18 @@ typedef enum eDriverTarget_Flag {
/* used for targets that use the pchan_name instead of RNA path
* (i.e. rotation difference)
*/
- DTAR_FLAG_STRUCT_REF = (1<<0),
+ DTAR_FLAG_STRUCT_REF = (1 << 0),
/* idtype can only be 'Object' */
- DTAR_FLAG_ID_OB_ONLY = (1<<1),
+ DTAR_FLAG_ID_OB_ONLY = (1 << 1),
/* "localspace" flags */
/* base flag - basically "pre parent+constraints" */
- DTAR_FLAG_LOCALSPACE = (1<<2),
+ DTAR_FLAG_LOCALSPACE = (1 << 2),
/* include constraints transformed to space including parents */
- DTAR_FLAG_LOCAL_CONSTS = (1<<3),
+ DTAR_FLAG_LOCAL_CONSTS = (1 << 3),
+
+ /* error flags */
+ DTAR_FLAG_INVALID = (1 << 4),
} eDriverTarget_Flag;
/* Transform Channels for Driver Targets */
diff --git a/source/blender/makesdna/DNA_controller_types.h b/source/blender/makesdna/DNA_controller_types.h
index bdfedb5b4d1..0c1aaf5fd20 100644
--- a/source/blender/makesdna/DNA_controller_types.h
+++ b/source/blender/makesdna/DNA_controller_types.h
@@ -27,6 +27,8 @@
/** \file DNA_controller_types.h
* \ingroup DNA
+ *
+ * #bController type is specifically for use by Object logic-bricks in the game-engine.
*/
#ifndef __DNA_CONTROLLER_TYPES_H__
@@ -89,5 +91,4 @@ typedef struct bController {
#define CONT_PY_SCRIPT 0
#define CONT_PY_MODULE 1
-#endif
-
+#endif /* __DNA_CONTROLLER_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index e28b8780250..4a3debe756b 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -27,6 +27,8 @@
/** \file DNA_customdata_types.h
* \ingroup DNA
+ *
+ * Used for custom mesh data types (stored per vert/edge/loop/face)
*/
#ifndef __DNA_CUSTOMDATA_TYPES_H__
@@ -177,4 +179,4 @@ typedef struct CustomData {
}
#endif
-#endif
+#endif /* __DNA_CUSTOMDATA_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_defs.h b/source/blender/makesdna/DNA_defs.h
index 774fbcf081a..ffe4fc970b1 100644
--- a/source/blender/makesdna/DNA_defs.h
+++ b/source/blender/makesdna/DNA_defs.h
@@ -22,6 +22,8 @@
/** \file DNA_defs.h
* \ingroup DNA
+ *
+ * Group generic defines for all DNA headers may use in this file.
*/
#ifndef __DNA_DEFS_H__
diff --git a/source/blender/makesdna/DNA_group_types.h b/source/blender/makesdna/DNA_group_types.h
index a084bee1c2d..2740281b4c0 100644
--- a/source/blender/makesdna/DNA_group_types.h
+++ b/source/blender/makesdna/DNA_group_types.h
@@ -27,6 +27,8 @@
/** \file DNA_group_types.h
* \ingroup DNA
+ *
+ * \brief Object groups, one object can be in many groups at once.
*/
#ifndef __DNA_GROUP_TYPES_H__
@@ -58,4 +60,4 @@ typedef struct Group {
float dupli_ofs[3];
} Group;
-#endif
+#endif /* __DNA_GROUP_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 682f54481fc..54ec07c1855 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -101,10 +101,12 @@ typedef struct Image {
float lastupdate;
int lastused;
short animspeed;
+ short pad2;
/* for generated images */
- short gen_x, gen_y;
+ int gen_x, gen_y;
char gen_type, gen_flag;
+ char gen_pad[2];
/* display aspect - for UV editing images resized for faster openGL display */
float aspx, aspy;
diff --git a/source/blender/makesdna/DNA_key_types.h b/source/blender/makesdna/DNA_key_types.h
index 6e5861043c1..4783247420c 100644
--- a/source/blender/makesdna/DNA_key_types.h
+++ b/source/blender/makesdna/DNA_key_types.h
@@ -29,6 +29,10 @@
/** \file DNA_key_types.h
* \ingroup DNA
+ *
+ * This file defines structures for Shape-Keys (not animation keyframes),
+ * attached to Mesh, Curve and Lattice Data. Even though Key's are ID blocks they
+ * aren't intended to be shared between multiple data blocks as with other ID types.
*/
#include "DNA_defs.h"
diff --git a/source/blender/makesdna/DNA_mask_types.h b/source/blender/makesdna/DNA_mask_types.h
index 5b25d1a072c..1b6b802f2de 100644
--- a/source/blender/makesdna/DNA_mask_types.h
+++ b/source/blender/makesdna/DNA_mask_types.h
@@ -30,6 +30,9 @@
* \ingroup DNA
* \since march-2012
* \author Sergey Sharybin
+ *
+ * Mask data-blocks are collections of 2D curves to be used
+ * for image masking in the compositor and sequencer.
*/
#ifndef __DNA_MASK_TYPES_H__
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 5aaf46a541f..62c997b72c6 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -854,4 +854,7 @@ typedef struct NodeShaderNormalMap {
#define CMP_NODE_MASK_MBLUR_SAMPLES_MAX 64
+/* image */
+#define CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT 1
+
#endif
diff --git a/source/blender/makesdna/DNA_property_types.h b/source/blender/makesdna/DNA_property_types.h
index c1b810cd42b..c8275a41404 100644
--- a/source/blender/makesdna/DNA_property_types.h
+++ b/source/blender/makesdna/DNA_property_types.h
@@ -31,6 +31,8 @@
* \author nzc
* \attention Renderrecipe and scene decription. The fact that there is a
* hierarchy here is a bit strange, and not desirable.
+ *
+ * #bProperty type is specifically for use by Objects game-logic.
*/
#ifndef __DNA_PROPERTY_TYPES_H__
@@ -60,5 +62,4 @@ typedef struct bProperty {
#define MAX_PROPSTRING 128
-#endif
-
+#endif /* __DNA_PROPERTY_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h
index c144bc4e588..4a96c324f04 100644
--- a/source/blender/makesdna/DNA_rigidbody_types.h
+++ b/source/blender/makesdna/DNA_rigidbody_types.h
@@ -80,9 +80,7 @@ typedef enum eRigidBodyWorld_Flag {
/* sim data needs to be rebuilt */
RBW_FLAG_NEEDS_REBUILD = (1 << 1),
/* usse split impulse when stepping the simulation */
- RBW_FLAG_USE_SPLIT_IMPULSE = (1 << 2),
- /* need to step simulation after frame update */
- RBW_FLAG_FRAME_UPDATE = (1 << 3)
+ RBW_FLAG_USE_SPLIT_IMPULSE = (1 << 2)
} eRigidBodyWorld_Flag;
/* ******************************** */
diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h
index 05927e3a486..d8cf80d047b 100644
--- a/source/blender/makesdna/DNA_sensor_types.h
+++ b/source/blender/makesdna/DNA_sensor_types.h
@@ -29,6 +29,8 @@
* \ingroup DNA
* \since mar-2001
* \author nzc
+ *
+ * #bSensor type is specifically for use by Object logic-bricks in the game-engine.
*/
#ifndef __DNA_SENSOR_TYPES_H__
@@ -324,5 +326,5 @@ typedef struct bJoystickSensor {
#define SENS_DELAY_REPEAT 1
// should match JOYINDEX_MAX in SCA_JoystickDefines.h */
#define SENS_JOY_MAXINDEX 8
-#endif
+#endif /* __DNA_SENSOR_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 0aa466f7245..455350d8310 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -28,6 +28,14 @@
* \ingroup DNA
* \since mar-2001
* \author nzc
+ *
+ * Structs for use by the 'Sequencer' (Video Editor)
+ *
+ * Note on terminology
+ * - #Sequence: video/effect/audio data you can select and manipulate in the sequencer.
+ * - #Sequence.machine: Strange name for the channel.
+ * - #Strip: The data referenced by the #Sequence
+ * - Meta Strip (SEQ_TYPE_META): Support for nesting Sequences.
*/
#ifndef __DNA_SEQUENCE_TYPES_H__
@@ -441,4 +449,4 @@ enum {
SEQUENCE_MASK_INPUT_ID = 1
};
-#endif
+#endif /* __DNA_SEQUENCE_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 4c1d2c638b9..4587ed948cf 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -28,6 +28,8 @@
* \ingroup DNA
* \since mar-2001
* \author nzc
+ *
+ * Structs for each of space type in the user interface.
*/
#ifndef __DNA_SPACE_TYPES_H__
@@ -498,6 +500,7 @@ typedef enum eSpaceSeq_Flag {
SEQ_DRAW_SAFE_MARGINS = (1 << 3),
SEQ_SHOW_GPENCIL = (1 << 4),
SEQ_NO_DRAW_CFRANUM = (1 << 5),
+ SEQ_USE_ALPHA = (1 << 6), /* use RGBA display mode for preview */
} eSpaceSeq_Flag;
/* sseq->view */
@@ -1004,8 +1007,8 @@ typedef struct SpaceUserPref {
ListBase regionbase; /* storage of regions for inactive spaces */
int spacetype;
- int pad;
-
+ char pad[3];
+ char filter_type;
char filter[64]; /* search term for filtering in the UI */
} SpaceUserPref;
@@ -1133,4 +1136,4 @@ typedef enum eSpace_Type {
#define IMG_SIZE_FALLBACK 256
-#endif
+#endif /* __DNA_SPACE_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h
index 3194adba3a0..8b18ecd7253 100644
--- a/source/blender/makesdna/DNA_text_types.h
+++ b/source/blender/makesdna/DNA_text_types.h
@@ -28,6 +28,9 @@
* \ingroup DNA
* \since mar-2001
* \author nzc
+ *
+ * Text blocks used for Python-Scripts, OpenShadingLanguage
+ * and arbitrary text data to store in blend files.
*/
#ifndef __DNA_TEXT_TYPES_H__
@@ -75,4 +78,4 @@ typedef struct Text {
#define TXT_FOLLOW 0x0200 /* always follow cursor (console) */
#define TXT_TABSTOSPACES 0x0400 /* use space instead of tabs */
-#endif
+#endif /* __DNA_TEXT_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h
index 8789a17a7f7..73cda070fd2 100644
--- a/source/blender/makesdna/DNA_tracking_types.h
+++ b/source/blender/makesdna/DNA_tracking_types.h
@@ -30,6 +30,8 @@
* \ingroup DNA
* \since may-2011
* \author Sergey Sharybin
+ *
+ * Structs used for camera tracking and the movie-clip editor.
*/
#ifndef __DNA_TRACKING_TYPES_H__
@@ -431,4 +433,4 @@ enum {
TRACKING_COVERAGE_OK = 2
};
-#endif
+#endif /* __DNA_TRACKING_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_vfont_types.h b/source/blender/makesdna/DNA_vfont_types.h
index 7aaeaf23db2..416c5f594a3 100644
--- a/source/blender/makesdna/DNA_vfont_types.h
+++ b/source/blender/makesdna/DNA_vfont_types.h
@@ -29,6 +29,9 @@
* \ingroup DNA
* \since mar-2001
* \author nzc
+ *
+ * Vector Fonts used for text in the 3D view-port
+ * (unrelated to text used to render the GUI).
*/
#ifndef __DNA_VFONT_TYPES_H__
@@ -63,5 +66,5 @@ typedef struct VFont {
#define FO_SELCHANGE 10
#define FO_BUILTIN_NAME "<builtin>"
-#endif
+#endif /* __DNA_VFONT_TYPES_H__ */
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 585e08ea706..44792951cad 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -290,6 +290,9 @@ add_executable(makesrna ${SRC} ${SRC_RNA_INC} ${SRC_DNA_INC})
target_link_libraries(makesrna bf_dna)
target_link_libraries(makesrna bf_dna_blenlib)
+# too many warnings with clang
+remove_cc_flag("-Wmissing-prototypes")
+
# Output rna_*_gen.c
# note (linux only): with crashes try add this after COMMAND: valgrind --leak-check=full --track-origins=yes
add_custom_command(
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index adfb096b25f..6035326e0ae 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -3196,18 +3196,16 @@ static int rna_raw_access(ReportList *reports, PointerRNA *ptr, PropertyRNA *pro
return 0;
}
+ /* check item array */
+ itemlen = RNA_property_array_length(&itemptr, itemprop);
+
/* dynamic array? need to get length per item */
if (itemprop->getlength) {
itemprop = NULL;
}
/* try to access as raw array */
else if (RNA_property_collection_raw_array(ptr, prop, itemprop, &out)) {
- int arraylen;
-
- /* check item array */
- itemlen = RNA_property_array_length(&itemptr, itemprop);
-
- arraylen = (itemlen == 0) ? 1 : itemlen;
+ int arraylen = (itemlen == 0) ? 1 : itemlen;
if (in.len != arraylen * out.len) {
BKE_reportf(reports, RPT_ERROR, "Array length mismatch (expected %d, got %d)",
out.len * arraylen, in.len);
@@ -4866,7 +4864,7 @@ static char *rna_pointer_as_string__bldata(PointerRNA *ptr)
}
}
-char *RNA_pointer_as_string(bContext *C, PointerRNA *ptr, PropertyRNA *prop_ptr, PointerRNA *ptr_prop)
+char *RNA_pointer_as_string(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *prop_ptr, PointerRNA *ptr_prop)
{
if (RNA_property_flag(prop_ptr) & PROP_IDPROPERTY) {
return rna_pointer_as_string__idprop(C, ptr_prop);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 1fff567f25c..73fe5f3a48d 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -2412,7 +2412,12 @@ static void def_cmp_image(StructRNA *srna)
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Image", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
+
+ prop = RNA_def_property(srna, "use_straight_alpha_output", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "custom1", CMP_NODE_IMAGE_USE_STRAIGHT_OUTPUT);
+ RNA_def_property_ui_text(prop, "Straight Alpha Output", "Put Node output buffer to straight alpha instead of premultiplied");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
/* NB: image user properties used in the UI are redefined in def_node_image_user,
* to trigger correct updates of the node editor. RNA design problem that prevents
* updates from nested structs ...
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index d6f3f594395..4bf5de03b05 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -2892,7 +2892,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_float_funcs(prop, "rna_PartSetting_linelentail_get", "rna_PartSetting_linelentail_set", NULL);
RNA_def_property_range(prop, 0.0f, 100000.0f);
RNA_def_property_ui_range(prop, 0.0f, 10.0f, 0.1, 3);
- RNA_def_property_ui_text(prop, "Back", "Length of the line's tail");
+ RNA_def_property_ui_text(prop, "Tail", "Length of the line's tail");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
prop = RNA_def_property(srna, "line_length_head", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 5931440b422..e2e373d8beb 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -299,19 +299,19 @@ static void rna_def_render_engine(BlenderRNA *brna)
/* final render callbacks */
func = RNA_def_function(srna, "update", NULL);
RNA_def_function_ui_description(func, "Export scene data for render");
- RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
RNA_def_pointer(func, "data", "BlendData", "", "");
RNA_def_pointer(func, "scene", "Scene", "", "");
func = RNA_def_function(srna, "render", NULL);
RNA_def_function_ui_description(func, "Render scene into an image");
- RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
RNA_def_pointer(func, "scene", "Scene", "", "");
/* viewport render callbacks */
func = RNA_def_function(srna, "view_update", NULL);
RNA_def_function_ui_description(func, "Update on data changes for viewport render");
- RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL);
+ RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE);
RNA_def_pointer(func, "context", "Context", "", "");
func = RNA_def_function(srna, "view_draw", NULL);
diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c
index f5cf247b5a1..171bc702bc5 100644
--- a/source/blender/makesrna/intern/rna_rigidbody.c
+++ b/source/blender/makesrna/intern/rna_rigidbody.c
@@ -234,6 +234,20 @@ static void rna_RigidBodyOb_collision_margin_set(PointerRNA *ptr, float value)
#endif
}
+static void rna_RigidBodyOb_collision_groups_set(PointerRNA *ptr, const int *values)
+{
+ RigidBodyOb *rbo = (RigidBodyOb *)ptr->data;
+ int i;
+
+ for (i = 0; i < 20; i++) {
+ if (values[i])
+ rbo->col_groups |= (1 << i);
+ else
+ rbo->col_groups &= ~(1 << i);
+ }
+ rbo->flag |= RBO_FLAG_NEEDS_VALIDATE;
+}
+
static void rna_RigidBodyOb_kinematic_state_set(PointerRNA *ptr, int value)
{
RigidBodyOb *rbo = (RigidBodyOb *)ptr->data;
@@ -812,6 +826,7 @@ static void rna_def_rigidbody_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "collision_groups", PROP_BOOLEAN, PROP_LAYER_MEMBER);
RNA_def_property_boolean_sdna(prop, NULL, "col_groups", 1);
RNA_def_property_array(prop, 20);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyOb_collision_groups_set");
RNA_def_property_ui_text(prop, "Collision Groups", "Collision Groups Rigid Body belongs to");
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
@@ -949,13 +964,13 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_motor_lin", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_MOTOR_LIN);
RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyCon_use_motor_lin_set");
- RNA_def_property_ui_text(prop, "Linear Motor", "Enables linear motor");
+ RNA_def_property_ui_text(prop, "Linear Motor", "Enable linear motor");
RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
prop = RNA_def_property(srna, "use_motor_ang", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_MOTOR_ANG);
RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyCon_use_motor_ang_set");
- RNA_def_property_ui_text(prop, "Angular Motor", "Enables angular motor");
+ RNA_def_property_ui_text(prop, "Angular Motor", "Enable angular motor");
RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset");
prop = RNA_def_property(srna, "limit_lin_x_lower", PROP_FLOAT, PROP_UNIT_LENGTH);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 20269005b3f..906c8853179 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -916,16 +916,13 @@ static EnumPropertyItem *rna_RenderSettings_qtcodecsettings_codecType_itemf(bCon
EnumPropertyItem tmp = {0, "", 0, "", ""};
QuicktimeCodecTypeDesc *codecTypeDesc;
int i = 1, totitem = 0;
- char id[5];
-
+
for (i = 0; i < quicktime_get_num_videocodecs(); i++) {
codecTypeDesc = quicktime_get_videocodecType_desc(i);
if (!codecTypeDesc) break;
-
+
tmp.value = codecTypeDesc->rnatmpvalue;
- *((int *)id) = codecTypeDesc->codecType;
- id[4] = 0;
- tmp.identifier = id;
+ tmp.identifier = codecTypeDesc->codecName;
tmp.name = codecTypeDesc->codecName;
RNA_enum_item_add(&item, &totitem, &tmp);
}
@@ -1586,8 +1583,8 @@ static void rna_def_tool_settings(BlenderRNA *brna)
static EnumPropertyItem draw_groupuser_items[] = {
{OB_DRAW_GROUPUSER_NONE, "NONE", 0, "None", ""},
- {OB_DRAW_GROUPUSER_ACTIVE, "ACTIVE", 0, "Active", "Show vertices with no weights in the actuve group"},
- {OB_DRAW_GROUPUSER_ALL, "ALL", 0, "All", "Show vertices with no weights in the any group"},
+ {OB_DRAW_GROUPUSER_ACTIVE, "ACTIVE", 0, "Active", "Show vertices with no weights in the active group"},
+ {OB_DRAW_GROUPUSER_ALL, "ALL", 0, "All", "Show vertices with no weights in any group"},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index b0df27b957b..b3619330e7a 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -111,6 +111,7 @@ static void rna_Scene_collada_export(
int include_material_textures,
int use_texture_copies,
+ int use_ngons,
int use_object_instantiation,
int sort_by_name,
int second_life)
@@ -118,7 +119,7 @@ static void rna_Scene_collada_export(
collada_export(scene, filepath, apply_modifiers, export_mesh_type, selected,
include_children, include_armatures, include_shapekeys, deform_bones_only,
active_uv_only, include_uv_textures, include_material_textures,
- use_texture_copies, use_object_instantiation, sort_by_name, second_life);
+ use_texture_copies, use_ngons, use_object_instantiation, sort_by_name, second_life);
}
#endif
@@ -160,6 +161,7 @@ void RNA_api_scene(StructRNA *srna)
parm = RNA_def_boolean(func, "include_material_textures", 0, "Include Material Textures", "Export textures assigned to the object Materials");
parm = RNA_def_boolean(func, "use_texture_copies", 0, "copy", "Copy textures to same folder where the .dae file is exported");
+ parm = RNA_def_boolean(func, "use_ngons", 1, "Use NGons", "Keep NGons in Export");
parm = RNA_def_boolean(func, "use_object_instantiation", 1, "Use Object Instances", "Instantiate multiple Objects from same Data");
parm = RNA_def_boolean(func, "sort_by_name", 0, "Sort by Object name", "Sort exported data by Object name");
parm = RNA_def_boolean(func, "second_life", 0, "Export for Second Life", "Compatibility mode for Second Life");
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 7dc2dbf3d03..f1f4c13731f 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -2249,6 +2249,13 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem preview_channels_items[] = {
+ {SEQ_USE_ALPHA, "COLOR_ALPHA", ICON_IMAGE_RGB_ALPHA, "Color and Alpha",
+ "Draw image with RGB colors and alpha transparency"},
+ {0, "COLOR", ICON_IMAGE_RGB, "Color", "Draw image with RGB colors"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "SpaceSequenceEditor", "Space");
RNA_def_struct_sdna(srna, "SpaceSeq");
RNA_def_struct_ui_text(srna, "Space Sequence Editor", "Sequence editor space data");
@@ -2266,7 +2273,7 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_enum_items(prop, display_mode_items);
RNA_def_property_ui_text(prop, "Display Mode", "View mode to use for displaying sequencer output");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
-
+
/* flags */
prop = RNA_def_property(srna, "show_frame_indicator", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SEQ_NO_DRAW_CFRANUM);
@@ -2311,7 +2318,13 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
"The channel number shown in the image preview. 0 is the result of all strips combined");
RNA_def_property_range(prop, -5, MAXSEQ);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
-
+
+ prop = RNA_def_property(srna, "preview_channels", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, preview_channels_items);
+ RNA_def_property_ui_text(prop, "Draw Channels", "Channels of the preview to draw");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
prop = RNA_def_property(srna, "draw_overexposed", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "zebra");
RNA_def_property_ui_text(prop, "Show Overexposed", "Show overexposed areas with zebra stripes");
@@ -3042,13 +3055,24 @@ static void rna_def_space_info(BlenderRNA *brna)
static void rna_def_space_userpref(BlenderRNA *brna)
{
+ static EnumPropertyItem filter_type_items[] = {
+ {0, "NAME", 0, "Name", "Filter based on the operator name"},
+ {1, "KEY", 0, "Key-Binding", "Filter based on key bindings"},
+ {0, NULL, 0, NULL, NULL}};
+
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "SpaceUserPreferences", "Space");
RNA_def_struct_sdna(srna, "SpaceUserPref");
RNA_def_struct_ui_text(srna, "Space User Preferences", "User preferences space data");
-
+
+ prop = RNA_def_property(srna, "filter_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "filter_type");
+ RNA_def_property_enum_items(prop, filter_type_items);
+ RNA_def_property_ui_text(prop, "Filter Type", "Filter method");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
+
prop = RNA_def_property(srna, "filter_text", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "filter");
RNA_def_property_ui_text(prop, "Filter", "Search term for filtering in the UI");
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index cd646f4849c..798395b9fef 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -579,6 +579,9 @@ static void rna_def_trackingSettings(BlenderRNA *brna)
{REFINE_FOCAL_LENGTH |
REFINE_PRINCIPAL_POINT, "FOCAL_LENGTH_PRINCIPAL_POINT", 0, "Focal Length, Optical Center",
"Refine focal length and optical center"},
+ {REFINE_RADIAL_DISTORTION_K1 |
+ REFINE_RADIAL_DISTORTION_K2, "RADIAL_K1_K2", 0, "K1, K2",
+ "Refine radial distortion K1 and K2"},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index 2530a230e0a..d5620f91d6e 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -137,13 +137,13 @@ static void sphere_do(
int i, defgrp_index;
int has_radius = 0;
short flag, type;
- float fac, facm, len = 0.0f;
+ float len = 0.0f;
+ float fac = cmd->fac;
+ float facm = 1.0f - fac;
+ const float fac_orig = fac;
float vec[3], center[3] = {0.0f, 0.0f, 0.0f};
float mat[4][4], imat[4][4];
- fac = cmd->fac;
- facm = 1.0f - fac;
-
flag = cmd->flag;
type = cmd->type; /* projection type: sphere or cylinder */
@@ -193,67 +193,6 @@ static void sphere_do(
if (len == 0.0f) len = 10.0f;
}
- /* ready to apply the effect, one vertex at a time;
- * tiny optimization: the code is separated (with parts repeated)
- * in two possible cases:
- * with or w/o a vgroup. With lots of if's in the code below,
- * further optimization's are possible, if needed */
- if (dvert) { /* with a vgroup */
- MDeformVert *dv = dvert;
- float fac_orig = fac;
- for (i = 0; i < numVerts; i++, dv++) {
- float tmp_co[3];
- float weight;
-
- copy_v3_v3(tmp_co, vertexCos[i]);
- if (ctrl_ob) {
- if (flag & MOD_CAST_USE_OB_TRANSFORM) {
- mul_m4_v3(mat, tmp_co);
- }
- else {
- sub_v3_v3(tmp_co, center);
- }
- }
-
- copy_v3_v3(vec, tmp_co);
-
- if (type == MOD_CAST_TYPE_CYLINDER)
- vec[2] = 0.0f;
-
- if (has_radius) {
- if (len_v3(vec) > cmd->radius) continue;
- }
-
- weight = defvert_find_weight(dv, defgrp_index);
- if (weight <= 0.0f) continue;
-
- fac = fac_orig * weight;
- facm = 1.0f - fac;
-
- normalize_v3(vec);
-
- if (flag & MOD_CAST_X)
- tmp_co[0] = fac * vec[0] * len + facm * tmp_co[0];
- if (flag & MOD_CAST_Y)
- tmp_co[1] = fac * vec[1] * len + facm * tmp_co[1];
- if (flag & MOD_CAST_Z)
- tmp_co[2] = fac * vec[2] * len + facm * tmp_co[2];
-
- if (ctrl_ob) {
- if (flag & MOD_CAST_USE_OB_TRANSFORM) {
- mul_m4_v3(imat, tmp_co);
- }
- else {
- add_v3_v3(tmp_co, center);
- }
- }
-
- copy_v3_v3(vertexCos[i], tmp_co);
- }
- return;
- }
-
- /* no vgroup */
for (i = 0; i < numVerts; i++) {
float tmp_co[3];
@@ -276,6 +215,16 @@ static void sphere_do(
if (len_v3(vec) > cmd->radius) continue;
}
+ if (dvert) {
+ const float weight = defvert_find_weight(&dvert[i], defgrp_index);
+ if (weight == 0.0f) {
+ continue;
+ }
+
+ fac = fac_orig * weight;
+ facm = 1.0f - fac;
+ }
+
normalize_v3(vec);
if (flag & MOD_CAST_X)
@@ -308,14 +257,13 @@ static void cuboid_do(
int i, defgrp_index;
int has_radius = 0;
short flag;
- float fac, facm;
+ float fac = cmd->fac;
+ float facm = 1.0f - fac;
+ const float fac_orig = fac;
float min[3], max[3], bb[8][3];
float center[3] = {0.0f, 0.0f, 0.0f};
float mat[4][4], imat[4][4];
- fac = cmd->fac;
- facm = 1.0f - fac;
-
flag = cmd->flag;
ctrl_ob = cmd->object;
@@ -397,118 +345,10 @@ static void cuboid_do(
bb[0][2] = bb[1][2] = bb[2][2] = bb[3][2] = min[2];
bb[4][2] = bb[5][2] = bb[6][2] = bb[7][2] = max[2];
- /* ready to apply the effect, one vertex at a time;
- * tiny optimization: the code is separated (with parts repeated)
- * in two possible cases:
- * with or w/o a vgroup. With lots of if's in the code below,
- * further optimization's are possible, if needed */
- if (dvert) { /* with a vgroup */
- float fac_orig = fac;
- for (i = 0; i < numVerts; i++) {
- MDeformWeight *dw = NULL;
- int j, octant, coord;
- float d[3], dmax, apex[3], fbb;
- float tmp_co[3];
-
- copy_v3_v3(tmp_co, vertexCos[i]);
- if (ctrl_ob) {
- if (flag & MOD_CAST_USE_OB_TRANSFORM) {
- mul_m4_v3(mat, tmp_co);
- }
- else {
- sub_v3_v3(tmp_co, center);
- }
- }
-
- if (has_radius) {
- if (fabsf(tmp_co[0]) > cmd->radius ||
- fabsf(tmp_co[1]) > cmd->radius ||
- fabsf(tmp_co[2]) > cmd->radius)
- {
- continue;
- }
- }
-
- for (j = 0; j < dvert[i].totweight; ++j) {
- if (dvert[i].dw[j].def_nr == defgrp_index) {
- dw = &dvert[i].dw[j];
- break;
- }
- }
- if (!dw) continue;
-
- fac = fac_orig * dw->weight;
- facm = 1.0f - fac;
-
- /* The algo used to project the vertices to their
- * bounding box (bb) is pretty simple:
- * for each vertex v:
- * 1) find in which octant v is in;
- * 2) find which outer "wall" of that octant is closer to v;
- * 3) calculate factor (var fbb) to project v to that wall;
- * 4) project. */
-
- /* find in which octant this vertex is in */
- octant = 0;
- if (tmp_co[0] > 0.0f) octant += 1;
- if (tmp_co[1] > 0.0f) octant += 2;
- if (tmp_co[2] > 0.0f) octant += 4;
-
- /* apex is the bb's vertex at the chosen octant */
- copy_v3_v3(apex, bb[octant]);
-
- /* find which bb plane is closest to this vertex ... */
- d[0] = tmp_co[0] / apex[0];
- d[1] = tmp_co[1] / apex[1];
- d[2] = tmp_co[2] / apex[2];
-
- /* ... (the closest has the higher (closer to 1) d value) */
- dmax = d[0];
- coord = 0;
- if (d[1] > dmax) {
- dmax = d[1];
- coord = 1;
- }
- if (d[2] > dmax) {
- /* dmax = d[2]; */ /* commented, we don't need it */
- coord = 2;
- }
-
- /* ok, now we know which coordinate of the vertex to use */
-
- if (fabsf(tmp_co[coord]) < FLT_EPSILON) /* avoid division by zero */
- continue;
-
- /* finally, this is the factor we wanted, to project the vertex
- * to its bounding box (bb) */
- fbb = apex[coord] / tmp_co[coord];
-
- /* calculate the new vertex position */
- if (flag & MOD_CAST_X)
- tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb;
- if (flag & MOD_CAST_Y)
- tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb;
- if (flag & MOD_CAST_Z)
- tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb;
-
- if (ctrl_ob) {
- if (flag & MOD_CAST_USE_OB_TRANSFORM) {
- mul_m4_v3(imat, tmp_co);
- }
- else {
- add_v3_v3(tmp_co, center);
- }
- }
-
- copy_v3_v3(vertexCos[i], tmp_co);
- }
- return;
- }
-
- /* no vgroup (check previous case for comments about the code) */
+ /* ready to apply the effect, one vertex at a time */
for (i = 0; i < numVerts; i++) {
int octant, coord;
- float d[3], dmax, fbb, apex[3];
+ float d[3], dmax, apex[3], fbb;
float tmp_co[3];
copy_v3_v3(tmp_co, vertexCos[i]);
@@ -530,17 +370,39 @@ static void cuboid_do(
}
}
+ if (dvert) {
+ const float weight = defvert_find_weight(&dvert[i], defgrp_index);
+ if (weight == 0.0f) {
+ continue;
+ }
+
+ fac = fac_orig * weight;
+ facm = 1.0f - fac;
+ }
+
+ /* The algo used to project the vertices to their
+ * bounding box (bb) is pretty simple:
+ * for each vertex v:
+ * 1) find in which octant v is in;
+ * 2) find which outer "wall" of that octant is closer to v;
+ * 3) calculate factor (var fbb) to project v to that wall;
+ * 4) project. */
+
+ /* find in which octant this vertex is in */
octant = 0;
if (tmp_co[0] > 0.0f) octant += 1;
if (tmp_co[1] > 0.0f) octant += 2;
if (tmp_co[2] > 0.0f) octant += 4;
+ /* apex is the bb's vertex at the chosen octant */
copy_v3_v3(apex, bb[octant]);
+ /* find which bb plane is closest to this vertex ... */
d[0] = tmp_co[0] / apex[0];
d[1] = tmp_co[1] / apex[1];
d[2] = tmp_co[2] / apex[2];
+ /* ... (the closest has the higher (closer to 1) d value) */
dmax = d[0];
coord = 0;
if (d[1] > dmax) {
@@ -552,11 +414,16 @@ static void cuboid_do(
coord = 2;
}
- if (fabsf(tmp_co[coord]) < FLT_EPSILON)
+ /* ok, now we know which coordinate of the vertex to use */
+
+ if (fabsf(tmp_co[coord]) < FLT_EPSILON) /* avoid division by zero */
continue;
+ /* finally, this is the factor we wanted, to project the vertex
+ * to its bounding box (bb) */
fbb = apex[coord] / tmp_co[coord];
+ /* calculate the new vertex position */
if (flag & MOD_CAST_X)
tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb;
if (flag & MOD_CAST_Y)
diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c
index 5e702a4eabc..be7bfae22fb 100644
--- a/source/blender/modifiers/intern/MOD_meshcache.c
+++ b/source/blender/modifiers/intern/MOD_meshcache.c
@@ -251,7 +251,7 @@ static void meshcache_do(
/* -------------------------------------------------------------------- */
/* Apply the transformation matrix (if needed) */
if (UNLIKELY(err_str)) {
- modifier_setError(&mcmd->modifier, err_str);
+ modifier_setError(&mcmd->modifier, "%s", err_str);
}
else if (ok) {
bool use_matrix = false;
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 038fb4913ec..a198eaf8ca9 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -29,6 +29,7 @@
* \ingroup modifiers
*/
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "MEM_guardedalloc.h"
@@ -598,6 +599,10 @@ static DerivedMesh *applyModifier(
int *orig_ed;
int j;
+ if (crease_rim || crease_outer || crease_inner) {
+ result->cd_flag |= ME_CDFLAG_EDGE_CREASE;
+ }
+
/* add faces & edges */
origindex_edge = result->getEdgeDataArray(result, CD_ORIGINDEX);
ed = &medge[numEdges * 2];
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index c0d46b14aa8..c48682b877e 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -107,6 +107,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
subsurf_flags |= SUBSURF_IN_EDIT_MODE;
result = subsurf_make_derived_from_derived(derivedData, smd, NULL, subsurf_flags);
+ result->cd_flag = derivedData->cd_flag;
if (useRenderParams || !isFinalCalc) {
DerivedMesh *cddm = CDDM_copy(result);
diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c
index 7a8b8c940c9..8cf7cc7a1ea 100644
--- a/source/blender/nodes/intern/node_exec.c
+++ b/source/blender/nodes/intern/node_exec.c
@@ -248,8 +248,9 @@ void ntree_exec_end(bNodeTreeExec *exec)
MEM_freeN(exec->stack);
for (n=0, nodeexec= exec->nodeexec; n < exec->totnodes; ++n, ++nodeexec) {
- if (nodeexec->node->typeinfo->freeexecfunc)
- nodeexec->node->typeinfo->freeexecfunc(nodeexec->node, nodeexec->data);
+ if (nodeexec->node->typeinfo)
+ if (nodeexec->node->typeinfo->freeexecfunc)
+ nodeexec->node->typeinfo->freeexecfunc(nodeexec->node, nodeexec->data);
}
if (exec->nodeexec)
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 19ec35ae357..cef4e23242d 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -4257,11 +4257,12 @@ static PyObject *pyrna_prop_collection_find(BPy_PropertyRNA *self, PyObject *key
return PyLong_FromLong(index);
}
-static void foreach_attr_type(BPy_PropertyRNA *self, const char *attr,
+static bool foreach_attr_type(BPy_PropertyRNA *self, const char *attr,
/* values to assign */
RawPropertyType *raw_type, int *attr_tot, bool *attr_signed)
{
PropertyRNA *prop;
+ bool attr_ok = true;
*raw_type = PROP_RAW_UNSET;
*attr_tot = 0;
*attr_signed = false;
@@ -4270,12 +4271,19 @@ static void foreach_attr_type(BPy_PropertyRNA *self, const char *attr,
RNA_PROP_BEGIN (&self->ptr, itemptr, self->prop)
{
prop = RNA_struct_find_property(&itemptr, attr);
- *raw_type = RNA_property_raw_type(prop);
- *attr_tot = RNA_property_array_length(&itemptr, prop);
- *attr_signed = (RNA_property_subtype(prop) == PROP_UNSIGNED) ? false : true;
+ if (prop) {
+ *raw_type = RNA_property_raw_type(prop);
+ *attr_tot = RNA_property_array_length(&itemptr, prop);
+ *attr_signed = (RNA_property_subtype(prop) != PROP_UNSIGNED);
+ }
+ else {
+ attr_ok = false;
+ }
break;
}
RNA_PROP_END;
+
+ return attr_ok;
}
/* pyrna_prop_collection_foreach_get/set both use this */
@@ -4295,15 +4303,26 @@ static int foreach_parse_args(BPy_PropertyRNA *self, PyObject *args,
*attr_signed = false;
*raw_type = PROP_RAW_UNSET;
- if (!PyArg_ParseTuple(args, "sO", attr, seq) || (!PySequence_Check(*seq) && PyObject_CheckBuffer(*seq))) {
- PyErr_SetString(PyExc_TypeError, "foreach_get(attr, sequence) expects a string and a sequence");
+ if (!PyArg_ParseTuple(args, "sO:foreach_get/set", attr, seq)) {
+ return -1;
+ }
+
+ if (!PySequence_Check(*seq) && PyObject_CheckBuffer(*seq)) {
+ PyErr_Format(PyExc_TypeError,
+ "foreach_get/set expected second argument to be a sequence or buffer, not a %.200s",
+ Py_TYPE(seq)->tp_name);
return -1;
}
*tot = PySequence_Size(*seq); /* TODO - buffer may not be a sequence! array.array() is tho. */
if (*tot > 0) {
- foreach_attr_type(self, *attr, raw_type, attr_tot, attr_signed);
+ if (!foreach_attr_type(self, *attr, raw_type, attr_tot, attr_signed)) {
+ PyErr_Format(PyExc_AttributeError,
+ "foreach_get/set '%.200s.%200s[...]' elements have no attribute '%.200s'",
+ RNA_struct_identifier(self->ptr.type), RNA_property_identifier(self->prop), *attr);
+ return -1;
+ }
*size = RNA_raw_type_sizeof(*raw_type);
#if 0 /* works fine but not strictly needed, we could allow RNA_property_collection_raw_* to do the checks */
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index a19f8e2d8ed..b61ed55da06 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -156,7 +156,8 @@ static int pyrna_struct_keyframe_parse(
/* note, parse_str MUST start with 's|ifsO!' */
if (!PyArg_ParseTupleAndKeywords(args, kw, parse_str, (char **)kwlist, &path, index, cfra, group_name,
- &PySet_Type, &pyoptions)) {
+ &PySet_Type, &pyoptions))
+ {
return -1;
}
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index effc564fdc9..12d36ccfdd2 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -166,7 +166,8 @@ if(WITH_GAMEENGINE)
endif()
if(APPLE)
- if(CMAKE_OSX_ARCHITECTURES MATCHES "i386" OR CMAKE_OSX_ARCHITECTURES MATCHES "x86_64")
+ # SSE math is enabled by default on x86_64
+ if(CMAKE_OSX_ARCHITECTURES MATCHES "i386")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -mfpmath=sse")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mfpmath=sse")
endif()
diff --git a/source/blender/render/intern/raytrace/reorganize.h b/source/blender/render/intern/raytrace/reorganize.h
index 9d9711eee56..5624df25267 100644
--- a/source/blender/render/intern/raytrace/reorganize.h
+++ b/source/blender/render/intern/raytrace/reorganize.h
@@ -80,7 +80,6 @@ void reorganize_find_fittest_parent(Node *tree, Node *node, std::pair<float, Nod
}
}
-static int tot_moves = 0;
template<class Node>
void reorganize(Node *root)
{
@@ -109,8 +108,6 @@ void reorganize(Node *root)
tmp->sibling = best.second->child;
best.second->child = tmp;
-
- tot_moves++;
}
diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c
index 747362a7974..1c594ef7db2 100644
--- a/source/blender/render/intern/source/occlusion.c
+++ b/source/blender/render/intern/source/occlusion.c
@@ -763,414 +763,6 @@ static float occ_solid_angle(OccNode *node, const float v[3], float d2, float in
return ((node->area * dotemit * dotreceive) / (d2 + node->area * INVPI)) * INVPI;
}
-static void vec_add_dir(float r[3], const float v1[3], const float v2[3], const float fac)
-{
- r[0] = v1[0] + fac * (v2[0] - v1[0]);
- r[1] = v1[1] + fac * (v2[1] - v1[1]);
- r[2] = v1[2] + fac * (v2[2] - v1[2]);
-}
-
-/* TODO: exact duplicate of ff_visible_quad() in math_geom.c
- * why not de-duplicate? (also above helper func) */
-static int occ_visible_quad(const float p[3], const float n[3],
- const float v0[3], const float v1[3], const float v2[3],
- float q0[3], float q1[3], float q2[3], float q3[3])
-{
- static const float epsilon = 1e-6f;
- float c, sd[3];
-
- c = dot_v3v3(n, p);
-
- /* signed distances from the vertices to the plane. */
- sd[0] = dot_v3v3(n, v0) - c;
- sd[1] = dot_v3v3(n, v1) - c;
- sd[2] = dot_v3v3(n, v2) - c;
-
- if (fabsf(sd[0]) < epsilon) sd[0] = 0.0f;
- if (fabsf(sd[1]) < epsilon) sd[1] = 0.0f;
- if (fabsf(sd[2]) < epsilon) sd[2] = 0.0f;
-
- if (sd[0] > 0) {
- if (sd[1] > 0) {
- if (sd[2] > 0) {
- /* +++ */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- else if (sd[2] < 0) {
- /* ++- */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- vec_add_dir(q2, v1, v2, (sd[1] / (sd[1] - sd[2])));
- vec_add_dir(q3, v0, v2, (sd[0] / (sd[0] - sd[2])));
- }
- else {
- /* ++0 */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- }
- else if (sd[1] < 0) {
- if (sd[2] > 0) {
- /* +-+ */
- copy_v3_v3(q0, v0);
- vec_add_dir(q1, v0, v1, (sd[0] / (sd[0] - sd[1])));
- vec_add_dir(q2, v1, v2, (sd[1] / (sd[1] - sd[2])));
- copy_v3_v3(q3, v2);
- }
- else if (sd[2] < 0) {
- /* +-- */
- copy_v3_v3(q0, v0);
- vec_add_dir(q1, v0, v1, (sd[0] / (sd[0] - sd[1])));
- vec_add_dir(q2, v0, v2, (sd[0] / (sd[0] - sd[2])));
- copy_v3_v3(q3, q2);
- }
- else {
- /* +-0 */
- copy_v3_v3(q0, v0);
- vec_add_dir(q1, v0, v1, (sd[0] / (sd[0] - sd[1])));
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- }
- else {
- if (sd[2] > 0) {
- /* +0+ */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- else if (sd[2] < 0) {
- /* +0- */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- vec_add_dir(q2, v0, v2, (sd[0] / (sd[0] - sd[2])));
- copy_v3_v3(q3, q2);
- }
- else {
- /* +00 */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- }
- }
- else if (sd[0] < 0) {
- if (sd[1] > 0) {
- if (sd[2] > 0) {
- /* -++ */
- vec_add_dir(q0, v0, v1, (sd[0] / (sd[0] - sd[1])));
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- vec_add_dir(q3, v0, v2, (sd[0] / (sd[0] - sd[2])));
- }
- else if (sd[2] < 0) {
- /* -+- */
- vec_add_dir(q0, v0, v1, (sd[0] / (sd[0] - sd[1])));
- copy_v3_v3(q1, v1);
- vec_add_dir(q2, v1, v2, (sd[1] / (sd[1] - sd[2])));
- copy_v3_v3(q3, q2);
- }
- else {
- /* -+0 */
- vec_add_dir(q0, v0, v1, (sd[0] / (sd[0] - sd[1])));
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- }
- else if (sd[1] < 0) {
- if (sd[2] > 0) {
- /* --+ */
- vec_add_dir(q0, v0, v2, (sd[0] / (sd[0] - sd[2])));
- vec_add_dir(q1, v1, v2, (sd[1] / (sd[1] - sd[2])));
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- else if (sd[2] < 0) {
- /* --- */
- return 0;
- }
- else {
- /* --0 */
- return 0;
- }
- }
- else {
- if (sd[2] > 0) {
- /* -0+ */
- vec_add_dir(q0, v0, v2, (sd[0] / (sd[0] - sd[2])));
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- else if (sd[2] < 0) {
- /* -0- */
- return 0;
- }
- else {
- /* -00 */
- return 0;
- }
- }
- }
- else {
- if (sd[1] > 0) {
- if (sd[2] > 0) {
- /* 0++ */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- else if (sd[2] < 0) {
- /* 0+- */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- vec_add_dir(q2, v1, v2, (sd[1] / (sd[1] - sd[2])));
- copy_v3_v3(q3, q2);
- }
- else {
- /* 0+0 */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- }
- else if (sd[1] < 0) {
- if (sd[2] > 0) {
- /* 0-+ */
- copy_v3_v3(q0, v0);
- vec_add_dir(q1, v1, v2, (sd[1] / (sd[1] - sd[2])));
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- else if (sd[2] < 0) {
- /* 0-- */
- return 0;
- }
- else {
- /* 0-0 */
- return 0;
- }
- }
- else {
- if (sd[2] > 0) {
- /* 00+ */
- copy_v3_v3(q0, v0);
- copy_v3_v3(q1, v1);
- copy_v3_v3(q2, v2);
- copy_v3_v3(q3, q2);
- }
- else if (sd[2] < 0) {
- /* 00- */
- return 0;
- }
- else {
- /* 000 */
- return 0;
- }
- }
- }
-
- return 1;
-}
-
-/* altivec optimization, this works, but is unused */
-
-#if 0
-#include <Accelerate/Accelerate.h>
-
-typedef union {
- vFloat v;
- float f[4];
-} vFloatResult;
-
-static vFloat vec_splat_float(float val)
-{
- return (vFloat) {val, val, val, val};
-}
-
-static float occ_quad_form_factor(float *p, float *n, float *q0, float *q1, float *q2, float *q3)
-{
- vFloat vcos, rlen, vrx, vry, vrz, vsrx, vsry, vsrz, gx, gy, gz, vangle;
- vUInt8 rotate = (vUInt8) {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3};
- vFloatResult vresult;
- float result;
-
- /* compute r* */
- vrx = (vFloat) {q0[0], q1[0], q2[0], q3[0]} -vec_splat_float(p[0]);
- vry = (vFloat) {q0[1], q1[1], q2[1], q3[1]} -vec_splat_float(p[1]);
- vrz = (vFloat) {q0[2], q1[2], q2[2], q3[2]} -vec_splat_float(p[2]);
-
- /* normalize r* */
- rlen = vec_rsqrte(vrx * vrx + vry * vry + vrz * vrz + vec_splat_float(1e-16f));
- vrx = vrx * rlen;
- vry = vry * rlen;
- vrz = vrz * rlen;
-
- /* rotate r* for cross and dot */
- vsrx = vec_perm(vrx, vrx, rotate);
- vsry = vec_perm(vry, vry, rotate);
- vsrz = vec_perm(vrz, vrz, rotate);
-
- /* cross product */
- gx = vsry * vrz - vsrz * vry;
- gy = vsrz * vrx - vsrx * vrz;
- gz = vsrx * vry - vsry * vrx;
-
- /* normalize */
- rlen = vec_rsqrte(gx * gx + gy * gy + gz * gz + vec_splat_float(1e-16f));
- gx = gx * rlen;
- gy = gy * rlen;
- gz = gz * rlen;
-
- /* angle */
- vcos = vrx * vsrx + vry * vsry + vrz * vsrz;
- vcos = vec_max(vec_min(vcos, vec_splat_float(1.0f)), vec_splat_float(-1.0f));
- vangle = vacosf(vcos);
-
- /* dot */
- vresult.v = (vec_splat_float(n[0]) * gx +
- vec_splat_float(n[1]) * gy +
- vec_splat_float(n[2]) * gz) * vangle;
-
- result = (vresult.f[0] + vresult.f[1] + vresult.f[2] + vresult.f[3]) * (0.5f / (float)M_PI);
- result = MAX2(result, 0.0f);
-
- return result;
-}
-
-#endif
-
-/* SSE optimization, acos code doesn't work */
-
-#if 0
-
-#include <xmmintrin.h>
-
-static __m128 sse_approx_acos(__m128 x)
-{
- /* needs a better approximation than taylor expansion of acos, since that
- * gives big erros for near 1.0 values, sqrt(2*x)*acos(1-x) should work
- * better, see http://www.tom.womack.net/projects/sse-fast-arctrig.html */
-
- return _mm_set_ps1(1.0f);
-}
-
-static float occ_quad_form_factor(float *p, float *n, float *q0, float *q1, float *q2, float *q3)
-{
- float r0[3], r1[3], r2[3], r3[3], g0[3], g1[3], g2[3], g3[3];
- float a1, a2, a3, a4, dot1, dot2, dot3, dot4, result;
- float fresult[4] __attribute__((aligned(16)));
- __m128 qx, qy, qz, rx, ry, rz, rlen, srx, sry, srz, gx, gy, gz, glen, rcos, angle, aresult;
-
- /* compute r */
- qx = _mm_set_ps(q3[0], q2[0], q1[0], q0[0]);
- qy = _mm_set_ps(q3[1], q2[1], q1[1], q0[1]);
- qz = _mm_set_ps(q3[2], q2[2], q1[2], q0[2]);
-
- rx = qx - _mm_set_ps1(p[0]);
- ry = qy - _mm_set_ps1(p[1]);
- rz = qz - _mm_set_ps1(p[2]);
-
- /* normalize r */
- rlen = _mm_rsqrt_ps(rx * rx + ry * ry + rz * rz + _mm_set_ps1(1e-16f));
- rx = rx * rlen;
- ry = ry * rlen;
- rz = rz * rlen;
-
- /* cross product */
- srx = _mm_shuffle_ps(rx, rx, _MM_SHUFFLE(0, 3, 2, 1));
- sry = _mm_shuffle_ps(ry, ry, _MM_SHUFFLE(0, 3, 2, 1));
- srz = _mm_shuffle_ps(rz, rz, _MM_SHUFFLE(0, 3, 2, 1));
-
- gx = sry * rz - srz * ry;
- gy = srz * rx - srx * rz;
- gz = srx * ry - sry * rx;
-
- /* normalize g */
- glen = _mm_rsqrt_ps(gx * gx + gy * gy + gz * gz + _mm_set_ps1(1e-16f));
- gx = gx * glen;
- gy = gy * glen;
- gz = gz * glen;
-
- /* compute angle */
- rcos = rx * srx + ry * sry + rz * srz;
- rcos = _mm_max_ps(_mm_min_ps(rcos, _mm_set_ps1(1.0f)), _mm_set_ps1(-1.0f));
-
- angle = sse_approx_cos(rcos);
- aresult = (_mm_set_ps1(n[0]) * gx + _mm_set_ps1(n[1]) * gy + _mm_set_ps1(n[2]) * gz) * angle;
-
- /* sum together */
- result = (fresult[0] + fresult[1] + fresult[2] + fresult[3]) * (0.5f / (float)M_PI);
- result = MAX2(result, 0.0f);
-
- return result;
-}
-
-#endif
-
-static void normalizef(float *n)
-{
- float d;
-
- d = dot_v3v3(n, n);
-
- if (d > 1.0e-35F) {
- d = 1.0f / sqrtf(d);
-
- n[0] *= d;
- n[1] *= d;
- n[2] *= d;
- }
-}
-
-/* TODO: exact duplicate of ff_quad_form_factor() in math_geom.c
- * why not de-duplicate? (also above helper func) */
-static float occ_quad_form_factor(const float p[3], const float n[3], const float q0[3], const float q1[3], const float q2[3], const float q3[3])
-{
- float r0[3], r1[3], r2[3], r3[3], g0[3], g1[3], g2[3], g3[3];
- float a1, a2, a3, a4, dot1, dot2, dot3, dot4, result;
-
- sub_v3_v3v3(r0, q0, p);
- sub_v3_v3v3(r1, q1, p);
- sub_v3_v3v3(r2, q2, p);
- sub_v3_v3v3(r3, q3, p);
-
- normalizef(r0);
- normalizef(r1);
- normalizef(r2);
- normalizef(r3);
-
- cross_v3_v3v3(g0, r1, r0); normalizef(g0);
- cross_v3_v3v3(g1, r2, r1); normalizef(g1);
- cross_v3_v3v3(g2, r3, r2); normalizef(g2);
- cross_v3_v3v3(g3, r0, r3); normalizef(g3);
-
- a1 = saacosf(dot_v3v3(r0, r1));
- a2 = saacosf(dot_v3v3(r1, r2));
- a3 = saacosf(dot_v3v3(r2, r3));
- a4 = saacosf(dot_v3v3(r3, r0));
-
- dot1 = dot_v3v3(n, g0);
- dot2 = dot_v3v3(n, g1);
- dot3 = dot_v3v3(n, g2);
- dot4 = dot_v3v3(n, g3);
-
- result = (a1 * dot1 + a2 * dot2 + a3 * dot3 + a4 * dot4) * 0.5f / (float)M_PI;
- result = MAX2(result, 0.0f);
-
- return result;
-}
-
static float occ_form_factor(OccFace *face, float *p, float *n)
{
ObjectInstanceRen *obi;
@@ -1190,16 +782,16 @@ static float occ_form_factor(OccFace *face, float *p, float *n)
mul_m4_v3(obi->mat, v3);
}
- if (occ_visible_quad(p, n, v1, v2, v3, q0, q1, q2, q3))
- contrib += occ_quad_form_factor(p, n, q0, q1, q2, q3);
+ if (form_factor_visible_quad(p, n, v1, v2, v3, q0, q1, q2, q3))
+ contrib += form_factor_quad(p, n, q0, q1, q2, q3);
if (vlr->v4) {
copy_v3_v3(v4, vlr->v4->co);
if (obi->flag & R_TRANSFORMED)
mul_m4_v3(obi->mat, v4);
- if (occ_visible_quad(p, n, v1, v3, v4, q0, q1, q2, q3))
- contrib += occ_quad_form_factor(p, n, q0, q1, q2, q3);
+ if (form_factor_visible_quad(p, n, v1, v3, v4, q0, q1, q2, q3))
+ contrib += form_factor_quad(p, n, q0, q1, q2, q3);
}
return contrib;
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 076bdaeaea7..ce18723b8c0 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -1457,7 +1457,7 @@ static void tag_scenes_for_render(Render *re)
Scene *scene = (Scene*) node->id;
if (scene->r.alphamode != R_ALPHAPREMUL) {
- BKE_reportf(re->reports, RPT_WARNING, "Setting scene %s alpha mode to Premul\n", scene->id.name + 2);
+ BKE_reportf(re->reports, RPT_WARNING, "Setting scene %s alpha mode to Premul", scene->id.name + 2);
/* also print, so feedback is immediate */
printf("2.66 versioning fix: setting scene %s alpha mode to Premul\n", scene->id.name + 2);
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index a1437b70090..57fe518dd46 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -308,7 +308,7 @@ void WM_gestures_remove(struct bContext *C);
void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op);
void WM_event_fileselect_event(struct bContext *C, void *ophandle, int eventval);
#ifndef NDEBUG
-void WM_event_print(struct wmEvent *event);
+void WM_event_print(const struct wmEvent *event);
#endif
void WM_operator_region_active_win_set(struct bContext *C);
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 6044e3fb771..173a8237c02 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -796,15 +796,18 @@ void wm_draw_update(bContext *C)
GPU_free_unused_buffers();
for (win = wm->windows.first; win; win = win->next) {
- int state = GHOST_GetWindowState(win->ghostwin);
-
- if (state == GHOST_kWindowStateMinimized) {
- /* do not update minimized windows, it gives issues on intel drivers (see [#33223])
- * anyway, it seems logical to skip update for invisible windows
- */
- continue;
+#ifdef WIN32
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ GHOST_TWindowState state = GHOST_GetWindowState(win->ghostwin);
+
+ if (state == GHOST_kWindowStateMinimized) {
+ /* do not update minimized windows, it gives issues on intel drivers (see [#33223])
+ * anyway, it seems logical to skip update for invisible windows
+ */
+ continue;
+ }
}
-
+#endif
if (win->drawmethod != U.wmdrawmethod) {
wm_draw_window_clear(win);
win->drawmethod = U.wmdrawmethod;
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 206297d2c95..4e181ec930b 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -472,7 +472,7 @@ void WM_operator_region_active_win_set(bContext *C)
/* for debugging only, getting inspecting events manually is tedious */
#ifndef NDEBUG
-void WM_event_print(wmEvent *event)
+void WM_event_print(const wmEvent *event)
{
if (event) {
const char *unknown = "UNKNOWN";
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 79257479529..678c77d0d88 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -110,6 +110,8 @@
static GHash *global_ops_hash = NULL;
+#define UNDOCUMENTED_OPERATOR_TIP N_("(undocumented operator)")
+
/* ************ operator API, exported ********** */
@@ -163,7 +165,7 @@ void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
}
/* XXX All ops should have a description but for now allow them not to. */
- RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : N_("(undocumented operator)"));
+ RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
RNA_def_struct_identifier(ot->srna, ot->idname);
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
@@ -178,7 +180,7 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
opfunc(ot, userdata);
- RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : N_("(undocumented operator)"));
+ RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
RNA_def_struct_identifier(ot->srna, ot->idname);
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
@@ -375,7 +377,7 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam
ot->poll = NULL;
if (!ot->description) /* XXX All ops should have a description but for now allow them not to. */
- ot->description = N_("(undocumented operator)");
+ ot->description = UNDOCUMENTED_OPERATOR_TIP;
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
RNA_def_struct_identifier(ot->srna, ot->idname);
@@ -401,7 +403,7 @@ void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *),
ot->poll = NULL;
if (!ot->description)
- ot->description = N_("(undocumented operator)");
+ ot->description = UNDOCUMENTED_OPERATOR_TIP;
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
@@ -1846,6 +1848,7 @@ static void WM_OT_call_menu(wmOperatorType *ot)
{
ot->name = "Call Menu";
ot->idname = "WM_OT_call_menu";
+ ot->description = "Call (draw) a pre-defined menu";
ot->exec = wm_call_menu_exec;
ot->poll = WM_operator_winactive;
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index fd44f4a7169..b510956dbc1 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -252,8 +252,15 @@ static void playanim_toscreen(PlayAnimPict *picture, struct ImBuf *ibuf, int fon
glRasterPos2f(0.0f, 0.0f);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ fdrawcheckerboard(0.0f, 0.0f, ibuf->x, ibuf->y);
+
glDrawPixels(ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ glDisable(GL_BLEND);
+
pupdate_time();
if (picture && (g_WS.qual & (WS_QUAL_SHIFT | WS_QUAL_LMOUSE)) && (fontid != -1)) {
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index fb06c5e4477..5e65324d893 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -103,7 +103,6 @@ endif()
ge_logic_ketsji
ge_phys_bullet
ge_phys_dummy
- ge_phys_common
ge_logic
ge_rasterizer
ge_oglrasterizer
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 7271e89461f..d858f7ac62d 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -844,12 +844,12 @@ endif()
bf_editor_util
bf_editor_uvedit
bf_editor_curve
- bf_editor_armature
bf_editor_gpencil
bf_editor_interface
bf_editor_mesh
bf_editor_metaball
bf_editor_object
+ bf_editor_armature
bf_editor_physics
bf_editor_render
bf_editor_screen
@@ -899,7 +899,6 @@ endif()
extern_colamd
ge_logic_ketsji
extern_recastnavigation
- ge_phys_common
ge_logic
ge_rasterizer
ge_oglrasterizer
diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
index e78b996391e..450ae1a16b5 100644
--- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
+++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
@@ -183,7 +183,7 @@ static int BL_KetsjiNextFrame(KX_KetsjiEngine *ketsjiengine, bContext *C, wmWind
}
struct BL_KetsjiNextFrameState {
- struct KX_KetsjiEngine* ketsjiengine;
+ class KX_KetsjiEngine* ketsjiengine;
struct bContext *C;
struct wmWindow* win;
struct Scene* scene;
diff --git a/source/gameengine/CMakeLists.txt b/source/gameengine/CMakeLists.txt
index aae7e93cc91..cf7895e98ea 100644
--- a/source/gameengine/CMakeLists.txt
+++ b/source/gameengine/CMakeLists.txt
@@ -37,7 +37,6 @@ add_subdirectory(Ketsji)
add_subdirectory(Ketsji/KXNetwork)
add_subdirectory(Network)
add_subdirectory(Network/LoopBackNetwork)
-add_subdirectory(Physics/common)
add_subdirectory(Physics/Dummy)
add_subdirectory(Rasterizer)
add_subdirectory(Rasterizer/RAS_OpenGLRasterizer)
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
index f861b105ba3..e3fd662e16f 100644
--- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
@@ -35,6 +35,8 @@
#endif
#include <math.h>
+#include <vector>
+#include <algorithm>
#include "BL_BlenderDataConversion.h"
#include "KX_BlenderGL.h"
@@ -506,12 +508,17 @@ static void GetUVs(BL_Material *material, MTF_localLayer *layers, MFace *mface,
uvs[0][0] = uvs[1][0] = uvs[2][0] = uvs[3][0] = MT_Point2(0.f, 0.f);
}
+ vector<STR_String> found_layers;
+
for (int vind = 0; vind<MAXTEX; vind++)
{
BL_Mapping &map = material->mapping[vind];
if (!(map.mapping & USEUV)) continue;
+ if (std::find(found_layers.begin(), found_layers.end(), map.uvCoName) != found_layers.end())
+ continue;
+
//If no UVSet is specified, try grabbing one from the UV/Image editor
if (map.uvCoName.IsEmpty() && tface)
{
@@ -544,6 +551,7 @@ static void GetUVs(BL_Material *material, MTF_localLayer *layers, MFace *mface,
uvs[3][unit].setValue(0.0f, 0.0f);
++unit;
+ found_layers.push_back(map.uvCoName);
break;
}
}
diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp
index dce62ad189a..8e729ffd7ae 100644
--- a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp
+++ b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp
@@ -81,7 +81,7 @@ SCA_Joystick *SCA_Joystick::GetInstance( short int joyindex )
return NULL;
#else /* WITH_SDL */
if (joyindex < 0 || joyindex >= JOYINDEX_MAX) {
- ECHO("Error-invalid joystick index: " << joyindex);
+ JOYSTICK_ECHO("Error-invalid joystick index: " << joyindex);
return NULL;
}
@@ -96,7 +96,7 @@ SCA_Joystick *SCA_Joystick::GetInstance( short int joyindex )
# else
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO) == -1 ) {
# endif
- ECHO("Error-Initializing-SDL: " << SDL_GetError());
+ JOYSTICK_ECHO("Error-Initializing-SDL: " << SDL_GetError());
return NULL;
}
@@ -242,7 +242,7 @@ bool SCA_Joystick::CreateJoystickDevice(void)
if (m_isinit == false) {
if (m_joyindex>=m_joynum) {
/* don't print a message, because this is done anyway */
- //ECHO("Joystick-Error: " << SDL_NumJoysticks() << " avaiable joystick(s)");
+ //JOYSTICK_ECHO("Joystick-Error: " << SDL_NumJoysticks() << " avaiable joystick(s)");
/* Need this so python args can return empty lists */
m_axismax = m_buttonmax = m_hatmax = 0;
@@ -253,7 +253,7 @@ bool SCA_Joystick::CreateJoystickDevice(void)
SDL_JoystickEventState(SDL_ENABLE);
m_isinit = true;
- ECHO("Joystick " << m_joyindex << " initialized");
+ JOYSTICK_ECHO("Joystick " << m_joyindex << " initialized");
/* must run after being initialized */
m_axismax = SDL_JoystickNumAxes(m_private->m_joystick);
@@ -279,7 +279,7 @@ void SCA_Joystick::DestroyJoystickDevice(void)
#ifdef WITH_SDL
if (m_isinit) {
if (SDL_JoystickOpened(m_joyindex)) {
- ECHO("Closing-joystick " << m_joyindex);
+ JOYSTICK_ECHO("Closing-joystick " << m_joyindex);
SDL_JoystickClose(m_private->m_joystick);
}
m_isinit = false;
diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h b/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h
index 148bdd0962e..37c867ef7d6 100644
--- a/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h
+++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h
@@ -37,10 +37,10 @@
#endif
#ifndef _DEBUG
-# define ECHO(x)
+# define JOYSTICK_ECHO(x)
#else
# include <iostream>
-# define ECHO(x) std::cout << x << std::endl;
+# define JOYSTICK_ECHO(x) std::cout << x << std::endl;
#endif
#define JOYINDEX_MAX 8
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
index 89d11515bb3..58710120afa 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
@@ -308,20 +308,21 @@ bool GPG_Application::startScreenSaverFullScreen(
#endif
-bool GPG_Application::startWindow(STR_String& title,
- int windowLeft,
- int windowTop,
- int windowWidth,
- int windowHeight,
- const bool stereoVisual,
- const int stereoMode,
- const GHOST_TUns16 samples)
+bool GPG_Application::startWindow(
+ STR_String& title,
+ int windowLeft,
+ int windowTop,
+ int windowWidth,
+ int windowHeight,
+ const bool stereoVisual,
+ const int stereoMode,
+ const GHOST_TUns16 samples)
{
bool success;
// Create the main window
//STR_String title ("Blender Player - GHOST");
m_mainWindow = fSystem->createWindow(title, windowLeft, windowTop, windowWidth, windowHeight, GHOST_kWindowStateNormal,
- GHOST_kDrawingContextTypeOpenGL, stereoVisual, samples);
+ GHOST_kDrawingContextTypeOpenGL, stereoVisual, false, samples);
if (!m_mainWindow) {
printf("error: could not create main window\n");
exit(-1);
@@ -340,16 +341,18 @@ bool GPG_Application::startWindow(STR_String& title,
return success;
}
-bool GPG_Application::startEmbeddedWindow(STR_String& title,
- const GHOST_TEmbedderWindowID parentWindow,
- const bool stereoVisual,
- const int stereoMode,
- const GHOST_TUns16 samples) {
+bool GPG_Application::startEmbeddedWindow(
+ STR_String& title,
+ const GHOST_TEmbedderWindowID parentWindow,
+ const bool stereoVisual,
+ const int stereoMode,
+ const GHOST_TUns16 samples)
+{
GHOST_TWindowState state = GHOST_kWindowStateNormal;
if (parentWindow != 0)
state = GHOST_kWindowStateEmbedded;
m_mainWindow = fSystem->createWindow(title, 0, 0, 0, 0, state,
- GHOST_kDrawingContextTypeOpenGL, stereoVisual, samples, parentWindow);
+ GHOST_kDrawingContextTypeOpenGL, stereoVisual, false, samples, parentWindow);
if (!m_mainWindow) {
printf("error: could not create main window\n");
@@ -366,13 +369,13 @@ bool GPG_Application::startEmbeddedWindow(STR_String& title,
bool GPG_Application::startFullScreen(
- int width,
- int height,
- int bpp,int frequency,
- const bool stereoVisual,
- const int stereoMode,
- const GHOST_TUns16 samples,
- bool useDesktop)
+ int width,
+ int height,
+ int bpp,int frequency,
+ const bool stereoVisual,
+ const int stereoMode,
+ const GHOST_TUns16 samples,
+ bool useDesktop)
{
bool success;
GHOST_TUns32 sysWidth=0, sysHeight=0;
@@ -386,6 +389,7 @@ bool GPG_Application::startFullScreen(
fSystem->beginFullScreen(setting, &m_mainWindow, stereoVisual, samples);
m_mainWindow->setCursorVisibility(false);
+ /* note that X11 ignores this (it uses a window internally for fullscreen) */
m_mainWindow->setState(GHOST_kWindowStateFullScreen);
success = initEngine(m_mainWindow, stereoMode);
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.h b/source/gameengine/GamePlayer/ghost/GPG_Application.h
index e04fcc2a555..f141443e738 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Application.h
+++ b/source/gameengine/GamePlayer/ghost/GPG_Application.h
@@ -61,23 +61,32 @@ public:
GPG_Application(GHOST_ISystem* system);
~GPG_Application(void);
- bool SetGameEngineData(struct Main* maggie, struct Scene* scene, GlobalSettings* gs, int argc, char** argv);
- bool startWindow(STR_String& title, int windowLeft, int windowTop, int windowWidth, int windowHeight,
- const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0);
- bool startFullScreen(int width, int height, int bpp, int frequency, const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0, bool useDesktop=false);
- bool startEmbeddedWindow(STR_String& title, const GHOST_TEmbedderWindowID parent_window, const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0);
+ bool SetGameEngineData(struct Main* maggie, struct Scene* scene, GlobalSettings* gs, int argc, char** argv);
+ bool startWindow(STR_String& title,
+ int windowLeft, int windowTop,
+ int windowWidth, int windowHeight,
+ const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0);
+ bool startFullScreen(int width, int height,
+ int bpp, int frequency,
+ const bool stereoVisual, const int stereoMode,
+ const GHOST_TUns16 samples=0, bool useDesktop=false);
+ bool startEmbeddedWindow(STR_String& title, const GHOST_TEmbedderWindowID parent_window,
+ const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0);
#ifdef WIN32
- bool startScreenSaverFullScreen(int width, int height, int bpp, int frequency, const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0);
- bool startScreenSaverPreview(HWND parentWindow, const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0);
+ bool startScreenSaverFullScreen(int width, int height,
+ int bpp, int frequency,
+ const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0);
+ bool startScreenSaverPreview(HWND parentWindow,
+ const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0);
#endif
virtual bool processEvent(GHOST_IEvent* event);
- int getExitRequested(void);
- const STR_String& getExitString(void);
- GlobalSettings* getGlobalSettings(void);
- bool StartGameEngine(int stereoMode);
- void StopGameEngine();
- void EngineNextFrame();
+ int getExitRequested(void);
+ const STR_String& getExitString(void);
+ GlobalSettings* getGlobalSettings(void);
+ bool StartGameEngine(int stereoMode);
+ void StopGameEngine();
+ void EngineNextFrame();
protected:
bool handleWheel(GHOST_IEvent* event);
@@ -165,4 +174,3 @@ protected:
int m_argc;
char** m_argv;
};
-
diff --git a/source/gameengine/Ketsji/BL_Action.cpp b/source/gameengine/Ketsji/BL_Action.cpp
index ff1f800a626..1a49f76e71a 100644
--- a/source/gameengine/Ketsji/BL_Action.cpp
+++ b/source/gameengine/Ketsji/BL_Action.cpp
@@ -176,11 +176,13 @@ bool BL_Action::Play(const char* name,
// Now try materials
if (m_obj->GetBlenderObject()->totcol==1) {
Material *mat = give_current_material(m_obj->GetBlenderObject(), 1);
- sg_contr = BL_CreateMaterialIpo(m_action, mat, 0, m_obj, kxscene->GetSceneConverter());
- if (sg_contr) {
- m_sg_contr_list.push_back(sg_contr);
- m_obj->GetSGNode()->AddSGController(sg_contr);
- sg_contr->SetObject(m_obj->GetSGNode());
+ if (mat) {
+ sg_contr = BL_CreateMaterialIpo(m_action, mat, 0, m_obj, kxscene->GetSceneConverter());
+ if (sg_contr) {
+ m_sg_contr_list.push_back(sg_contr);
+ m_obj->GetSGNode()->AddSGController(sg_contr);
+ sg_contr->SetObject(m_obj->GetSGNode());
+ }
}
} else {
Material *mat;
@@ -188,12 +190,14 @@ bool BL_Action::Play(const char* name,
for (int matidx = 1; matidx <= m_obj->GetBlenderObject()->totcol; ++matidx) {
mat = give_current_material(m_obj->GetBlenderObject(), matidx);
- matname = mat->id.name;
- sg_contr = BL_CreateMaterialIpo(m_action, mat, matname.hash(), m_obj, kxscene->GetSceneConverter());
- if (sg_contr) {
- m_sg_contr_list.push_back(sg_contr);
- m_obj->GetSGNode()->AddSGController(sg_contr);
- sg_contr->SetObject(m_obj->GetSGNode());
+ if (mat) {
+ matname = mat->id.name;
+ sg_contr = BL_CreateMaterialIpo(m_action, mat, matname.hash(), m_obj, kxscene->GetSceneConverter());
+ if (sg_contr) {
+ m_sg_contr_list.push_back(sg_contr);
+ m_obj->GetSGNode()->AddSGController(sg_contr);
+ sg_contr->SetObject(m_obj->GetSGNode());
+ }
}
}
}
diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp
index 64e191fe960..f5f9b344b87 100644
--- a/source/gameengine/Ketsji/BL_BlenderShader.cpp
+++ b/source/gameengine/Ketsji/BL_BlenderShader.cpp
@@ -80,7 +80,7 @@ void BL_BlenderShader::SetAttribs(RAS_IRasterizer* ras, const BL_Material *mat)
{
GPUVertexAttribs attribs;
GPUMaterial *gpumat;
- int i, attrib_num;
+ int i, attrib_num, uv = 0;
ras->SetAttribNum(0);
@@ -103,7 +103,7 @@ void BL_BlenderShader::SetAttribs(RAS_IRasterizer* ras, const BL_Material *mat)
continue;
if (attribs.layer[i].type == CD_MTFACE)
- ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_UV, attribs.layer[i].glindex);
+ ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_UV, attribs.layer[i].glindex, uv++);
else if (attribs.layer[i].type == CD_TANGENT)
ras->SetAttrib(RAS_IRasterizer::RAS_TEXTANGENT, attribs.layer[i].glindex);
else if (attribs.layer[i].type == CD_ORCO)
diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt
index 7f748013648..fa40dad21e7 100644
--- a/source/gameengine/Ketsji/CMakeLists.txt
+++ b/source/gameengine/Ketsji/CMakeLists.txt
@@ -222,6 +222,18 @@ set(SRC
KX_VisibilityActuator.h
KX_WorldInfo.h
KX_WorldIpoController.h
+
+ # orphan headers (not apart of a library)
+ ../Physics/common/PHY_DynamicTypes.h
+ ../Physics/common/PHY_ICharacter.h
+ ../Physics/common/PHY_IController.h
+ ../Physics/common/PHY_IGraphicController.h
+ ../Physics/common/PHY_IMotionState.h
+ ../Physics/common/PHY_IPhysicsController.h
+ ../Physics/common/PHY_IPhysicsEnvironment.h
+ ../Physics/common/PHY_IVehicle.h
+ ../Physics/common/PHY_Pro.h
+
)
add_definitions(-DGLEW_STATIC)
diff --git a/source/gameengine/Ketsji/KX_IpoConvert.cpp b/source/gameengine/Ketsji/KX_IpoConvert.cpp
index 9ec354ec840..57130bf57b2 100644
--- a/source/gameengine/Ketsji/KX_IpoConvert.cpp
+++ b/source/gameengine/Ketsji/KX_IpoConvert.cpp
@@ -25,7 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file gameengine/Converter/KX_IpoConvert.cpp
+/** \file gameengine/Ketsji/KX_IpoConvert.cpp
* \ingroup bgeconv
*/
diff --git a/source/gameengine/Ketsji/KX_IpoConvert.h b/source/gameengine/Ketsji/KX_IpoConvert.h
index 1f4e1bea96d..a653e4e110b 100644
--- a/source/gameengine/Ketsji/KX_IpoConvert.h
+++ b/source/gameengine/Ketsji/KX_IpoConvert.h
@@ -59,7 +59,7 @@ SG_Controller *BL_CreateCameraIPO(bAction *action,
SG_Controller *BL_CreateMaterialIpo(
bAction *action,
- class Material* blendermaterial,
+ struct Material* blendermaterial,
dword matname_hash,
KX_GameObject* gameobj,
KX_BlenderSceneConverter *converter);
diff --git a/source/gameengine/Physics/common/CMakeLists.txt b/source/gameengine/Physics/common/CMakeLists.txt
deleted file mode 100644
index 5e0e5964ca0..00000000000
--- a/source/gameengine/Physics/common/CMakeLists.txt
+++ /dev/null
@@ -1,55 +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
- .
- ../Dummy
- ../../../../intern/moto/include
-)
-
-set(INC_SYS
-
-)
-
-set(SRC
- PHY_IMotionState.cpp
- PHY_IController.cpp
- PHY_IPhysicsController.cpp
- PHY_IGraphicController.cpp
- PHY_IPhysicsEnvironment.cpp
- PHY_IVehicle.cpp
-
- PHY_DynamicTypes.h
- PHY_ICharacter.h
- PHY_IController.h
- PHY_IGraphicController.h
- PHY_IMotionState.h
- PHY_IPhysicsController.h
- PHY_IPhysicsEnvironment.h
- PHY_IVehicle.h
- PHY_Pro.h
-)
-
-blender_add_lib(ge_phys_common "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/gameengine/Physics/common/PHY_IController.cpp b/source/gameengine/Physics/common/PHY_IController.cpp
deleted file mode 100644
index 8568ffa74e6..00000000000
--- a/source/gameengine/Physics/common/PHY_IController.cpp
+++ /dev/null
@@ -1,38 +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/Physics/common/PHY_IController.cpp
- * \ingroup phys
- */
-
-#include "PHY_IController.h"
-
-PHY_IController::~PHY_IController()
-{
-
-}
-
diff --git a/source/gameengine/Physics/common/PHY_IController.h b/source/gameengine/Physics/common/PHY_IController.h
index 77864b740bd..ae1b2d9ad53 100644
--- a/source/gameengine/Physics/common/PHY_IController.h
+++ b/source/gameengine/Physics/common/PHY_IController.h
@@ -48,7 +48,7 @@ class PHY_IPhysicsEnvironment;
class PHY_IController
{
public:
- virtual ~PHY_IController();
+ virtual ~PHY_IController(){};
// clientinfo for raycasts for example
virtual void* getNewClientInfo()=0;
virtual void setNewClientInfo(void* clientinfo)=0;
diff --git a/source/gameengine/Physics/common/PHY_IGraphicController.cpp b/source/gameengine/Physics/common/PHY_IGraphicController.cpp
deleted file mode 100644
index 0b8f89ceed2..00000000000
--- a/source/gameengine/Physics/common/PHY_IGraphicController.cpp
+++ /dev/null
@@ -1,38 +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/Physics/common/PHY_IGraphicController.cpp
- * \ingroup phys
- */
-
-#include "PHY_IGraphicController.h"
-
-PHY_IGraphicController::~PHY_IGraphicController()
-{
-
-}
-
diff --git a/source/gameengine/Physics/common/PHY_IGraphicController.h b/source/gameengine/Physics/common/PHY_IGraphicController.h
index 8c38eebe283..5f64e7ccc80 100644
--- a/source/gameengine/Physics/common/PHY_IGraphicController.h
+++ b/source/gameengine/Physics/common/PHY_IGraphicController.h
@@ -42,7 +42,6 @@
class PHY_IGraphicController : public PHY_IController
{
public:
- virtual ~PHY_IGraphicController();
/**
* SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding')
*/
diff --git a/source/gameengine/Physics/common/PHY_IMotionState.cpp b/source/gameengine/Physics/common/PHY_IMotionState.cpp
deleted file mode 100644
index 1953e748bc0..00000000000
--- a/source/gameengine/Physics/common/PHY_IMotionState.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 gameengine/Physics/common/PHY_IMotionState.cpp
- * \ingroup phys
- */
-
-#include "PHY_IMotionState.h"
-
-PHY_IMotionState::~PHY_IMotionState()
-{
-
-}
diff --git a/source/gameengine/Physics/common/PHY_IMotionState.h b/source/gameengine/Physics/common/PHY_IMotionState.h
index 61ed87362c0..be5b2b54907 100644
--- a/source/gameengine/Physics/common/PHY_IMotionState.h
+++ b/source/gameengine/Physics/common/PHY_IMotionState.h
@@ -44,7 +44,7 @@ class PHY_IMotionState
{
public:
- virtual ~PHY_IMotionState();
+ virtual ~PHY_IMotionState(){};
virtual void getWorldPosition(float& posX,float& posY,float& posZ)=0;
virtual void getWorldScaling(float& scaleX,float& scaleY,float& scaleZ)=0;
diff --git a/source/gameengine/Physics/common/PHY_IPhysicsController.cpp b/source/gameengine/Physics/common/PHY_IPhysicsController.cpp
deleted file mode 100644
index 58b94df6221..00000000000
--- a/source/gameengine/Physics/common/PHY_IPhysicsController.cpp
+++ /dev/null
@@ -1,38 +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/Physics/common/PHY_IPhysicsController.cpp
- * \ingroup phys
- */
-
-#include "PHY_IPhysicsController.h"
-
-PHY_IPhysicsController::~PHY_IPhysicsController()
-{
-
-}
-
diff --git a/source/gameengine/Physics/common/PHY_IPhysicsController.h b/source/gameengine/Physics/common/PHY_IPhysicsController.h
index e6f26bc5b1b..18af42adc15 100644
--- a/source/gameengine/Physics/common/PHY_IPhysicsController.h
+++ b/source/gameengine/Physics/common/PHY_IPhysicsController.h
@@ -45,7 +45,7 @@ class PHY_IPhysicsController : public PHY_IController
{
public:
- virtual ~PHY_IPhysicsController();
+ virtual ~PHY_IPhysicsController(){};
/**
* SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding')
*/
diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.cpp b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.cpp
deleted file mode 100644
index 110ffc705fe..00000000000
--- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.cpp
+++ /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) 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/Physics/common/PHY_IPhysicsEnvironment.cpp
- * \ingroup phys
- */
-
-
-#include "PHY_IPhysicsEnvironment.h"
-
-/**
- * Physics Environment takes care of stepping the simulation and is a container for physics entities
- * (rigidbodies,constraints, materials etc.)
- * A derived class may be able to 'construct' entities by loading and/or converting
- */
-
-
-
-PHY_IPhysicsEnvironment::~PHY_IPhysicsEnvironment()
-{
-
-}
diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
index e7560ea02cc..14904a70553 100644
--- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
+++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
@@ -105,7 +105,7 @@ public:
class PHY_IPhysicsEnvironment
{
public:
- virtual ~PHY_IPhysicsEnvironment();
+ virtual ~PHY_IPhysicsEnvironment(){};
virtual void beginFrame() = 0;
virtual void endFrame() = 0;
/// Perform an integration step of duration 'timeStep'.
diff --git a/source/gameengine/Physics/common/PHY_IVehicle.cpp b/source/gameengine/Physics/common/PHY_IVehicle.cpp
deleted file mode 100644
index a60bb3e596d..00000000000
--- a/source/gameengine/Physics/common/PHY_IVehicle.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-/** \file gameengine/Physics/common/PHY_IVehicle.cpp
- * \ingroup phys
- */
-
-#include "PHY_IVehicle.h"
-
-PHY_IVehicle::~PHY_IVehicle()
-{
-
-}
diff --git a/source/gameengine/Physics/common/PHY_IVehicle.h b/source/gameengine/Physics/common/PHY_IVehicle.h
index 624f435c9f0..1dcec69a335 100644
--- a/source/gameengine/Physics/common/PHY_IVehicle.h
+++ b/source/gameengine/Physics/common/PHY_IVehicle.h
@@ -18,7 +18,7 @@ class PHY_IMotionState;
class PHY_IVehicle
{
public:
- virtual ~PHY_IVehicle();
+ virtual ~PHY_IVehicle(){};
virtual void AddWheel(
PHY_IMotionState* motionState,
diff --git a/source/gameengine/Physics/common/SConscript b/source/gameengine/Physics/common/SConscript
deleted file mode 100644
index aee5e444079..00000000000
--- a/source/gameengine/Physics/common/SConscript
+++ /dev/null
@@ -1,40 +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 = 'PHY_IMotionState.cpp PHY_IController.cpp PHY_IPhysicsController.cpp PHY_IGraphicController.cpp PHY_IPhysicsEnvironment.cpp PHY_IVehicle.cpp'
-
-incs = '. ../Dummy #intern/moto/include'
-
-defs = []
-
-if env['WITH_BF_CXX_GUARDEDALLOC']:
- defs.append('WITH_CXX_GUARDEDALLOC')
- incs += ' #intern/guardedalloc'
-
-env.BlenderLib ( 'ge_phys_common', Split(sources), Split(incs), defs, libtype=['core','player'], priority=[360,55], cxx_compileflags=env['BGE_CXXFLAGS'])
diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h
index 99026fa259a..c04b62bc5da 100644
--- a/source/gameengine/Rasterizer/RAS_IRasterizer.h
+++ b/source/gameengine/Rasterizer/RAS_IRasterizer.h
@@ -396,7 +396,7 @@ public:
virtual void SetTexCoordNum(int num) = 0;
virtual void SetAttribNum(int num) = 0;
virtual void SetTexCoord(TexCoGen coords, int unit) = 0;
- virtual void SetAttrib(TexCoGen coords, int unit) = 0;
+ virtual void SetAttrib(TexCoGen coords, int unit, int layer = 0) = 0;
virtual const MT_Matrix4x4& GetViewMatrix() const = 0;
virtual const MT_Matrix4x4& GetViewInvMatrix() const = 0;
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
index 0186e99f78a..f995f7ddb3d 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
@@ -116,19 +116,19 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas, int storage)
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_failsafe_storage = new RAS_StorageIM(&m_texco_num, m_texco, &m_attrib_num, m_attrib);
+ 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))
{
- m_storage = new RAS_StorageVA(&m_texco_num, m_texco, &m_attrib_num, m_attrib);
- m_failsafe_storage = new RAS_StorageIM(&m_texco_num, m_texco, &m_attrib_num, m_attrib);
+ 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_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;
}
}
@@ -740,11 +740,13 @@ void RAS_OpenGLRasterizer::SetTexCoord(TexCoGen coords, int unit)
m_texco[unit] = coords;
}
-void RAS_OpenGLRasterizer::SetAttrib(TexCoGen coords, int unit)
+void RAS_OpenGLRasterizer::SetAttrib(TexCoGen coords, int unit, int layer)
{
// this changes from material to material
- if (unit < RAS_MAX_ATTRIB)
+ if (unit < RAS_MAX_ATTRIB) {
m_attrib[unit] = coords;
+ m_attrib_layer[unit] = layer;
+ }
}
void RAS_OpenGLRasterizer::IndexPrimitives(RAS_MeshSlot& ms)
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
index 64c07358d95..94589f84197 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
@@ -109,6 +109,7 @@ protected:
int m_drawingmode;
TexCoGen m_texco[RAS_MAX_TEXCO];
TexCoGen m_attrib[RAS_MAX_ATTRIB];
+ int m_attrib_layer[RAS_MAX_ATTRIB];
int m_texco_num;
int m_attrib_num;
//int m_last_alphablend;
@@ -296,7 +297,7 @@ public:
virtual void SetTexCoordNum(int num);
virtual void SetAttribNum(int num);
virtual void SetTexCoord(TexCoGen coords, int unit);
- virtual void SetAttrib(TexCoGen coords, int unit);
+ virtual void SetAttrib(TexCoGen coords, int unit, int layer = 0);
void TexCoord(const RAS_TexVert &tv);
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp
index 7bcc8dc9034..900d6f387ff 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp
@@ -39,11 +39,12 @@ extern "C"{
#include "BKE_DerivedMesh.h"
}
-RAS_StorageIM::RAS_StorageIM(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib) :
+RAS_StorageIM::RAS_StorageIM(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer) :
m_texco_num(texco_num),
m_attrib_num(attrib_num),
m_texco(texco),
- m_attrib(attrib)
+ m_attrib(attrib),
+ m_attrib_layer(attrib_layer)
{
}
RAS_StorageIM::~RAS_StorageIM()
@@ -95,7 +96,6 @@ void RAS_StorageIM::TexCoord(const RAS_TexVert &tv)
}
if (GLEW_ARB_vertex_program) {
- int uv = 0;
for (unit = 0; unit < *m_attrib_num; unit++) {
switch (m_attrib[unit]) {
case RAS_IRasterizer::RAS_TEXCO_ORCO:
@@ -103,7 +103,7 @@ void RAS_StorageIM::TexCoord(const RAS_TexVert &tv)
glVertexAttrib3fvARB(unit, tv.getXYZ());
break;
case RAS_IRasterizer::RAS_TEXCO_UV:
- glVertexAttrib2fvARB(unit, tv.getUV(uv++));
+ glVertexAttrib2fvARB(unit, tv.getUV(m_attrib_layer[unit]));
break;
case RAS_IRasterizer::RAS_TEXCO_NORM:
glVertexAttrib3fvARB(unit, tv.getNormal());
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.h
index de4ff30d394..54ba2a57b61 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.h
@@ -34,7 +34,7 @@
class RAS_StorageIM : public RAS_IStorage
{
public:
- RAS_StorageIM(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib);
+ 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();
@@ -51,6 +51,7 @@ protected:
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);
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
index 7182525ea71..d45365dde04 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
@@ -29,13 +29,14 @@
#include "GL/glew.h"
-RAS_StorageVA::RAS_StorageVA(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib) :
+RAS_StorageVA::RAS_StorageVA(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer) :
m_texco_num(texco_num),
m_attrib_num(attrib_num),
m_last_texco_num(0),
m_last_attrib_num(0),
m_texco(texco),
- m_attrib(attrib)
+ m_attrib(attrib),
+ m_attrib_layer(attrib_layer)
{
}
@@ -214,7 +215,6 @@ void RAS_StorageVA::TexCoordPtr(const RAS_TexVert *tv)
}
if (GLEW_ARB_vertex_program) {
- int uv = 0;
for (unit = 0; unit < *m_attrib_num; unit++) {
switch (m_attrib[unit]) {
case RAS_IRasterizer::RAS_TEXCO_ORCO:
@@ -222,7 +222,7 @@ void RAS_StorageVA::TexCoordPtr(const RAS_TexVert *tv)
glVertexAttribPointerARB(unit, 3, GL_FLOAT, GL_FALSE, sizeof(RAS_TexVert), tv->getXYZ());
break;
case RAS_IRasterizer::RAS_TEXCO_UV:
- glVertexAttribPointerARB(unit, 2, GL_FLOAT, GL_FALSE, sizeof(RAS_TexVert), tv->getUV(uv++));
+ glVertexAttribPointerARB(unit, 2, GL_FLOAT, GL_FALSE, sizeof(RAS_TexVert), tv->getUV(m_attrib_layer[unit]));
break;
case RAS_IRasterizer::RAS_TEXCO_NORM:
glVertexAttribPointerARB(unit, 3, GL_FLOAT, GL_FALSE, sizeof(RAS_TexVert), tv->getNormal());
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h
index da7766ec5ca..e4d00310a11 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h
@@ -37,7 +37,7 @@ class RAS_StorageVA : public RAS_IStorage
{
public:
- RAS_StorageVA(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib);
+ RAS_StorageVA(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer);
virtual ~RAS_StorageVA();
virtual bool Init();
@@ -59,6 +59,7 @@ protected:
RAS_IRasterizer::TexCoGen* m_texco;
RAS_IRasterizer::TexCoGen* m_attrib;
+ int* m_attrib_layer;
RAS_IRasterizer::TexCoGen m_last_texco[RAS_MAX_TEXCO];
RAS_IRasterizer::TexCoGen m_last_attrib[RAS_MAX_ATTRIB];
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
index 077dfad80bb..3de77951fa7 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
@@ -101,10 +101,10 @@ void VBO::UpdateIndices()
glBufferData(GL_ELEMENT_ARRAY_BUFFER, space, &data->m_index[0], GL_STATIC_DRAW);
}
-void VBO::Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num, RAS_IRasterizer::TexCoGen* attrib, bool multi)
+void VBO::Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num, RAS_IRasterizer::TexCoGen* attrib, int *attrib_layer, bool multi)
{
int unit;
-
+
// Bind buffers
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, this->ibo);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->vbo_id);
@@ -159,7 +159,6 @@ void VBO::Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num,
if (GLEW_ARB_vertex_program)
{
- int uv = 0;
for (unit = 0; unit < attrib_num; ++unit)
{
switch (attrib[unit]) {
@@ -169,8 +168,7 @@ void VBO::Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num,
glEnableVertexAttribArrayARB(unit);
break;
case RAS_IRasterizer::RAS_TEXCO_UV:
- glVertexAttribPointerARB(unit, 2, GL_FLOAT, GL_FALSE, this->stride, (void*)((intptr_t)this->uv_offset+uv));
- uv += sizeof(GLfloat)*2;
+ glVertexAttribPointerARB(unit, 2, GL_FLOAT, GL_FALSE, this->stride, (void*)((intptr_t)this->uv_offset+attrib_layer[unit]*sizeof(GLfloat)*2));
glEnableVertexAttribArrayARB(unit);
break;
case RAS_IRasterizer::RAS_TEXCO_NORM:
@@ -204,11 +202,12 @@ void VBO::Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num,
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
}
-RAS_StorageVBO::RAS_StorageVBO(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib):
+RAS_StorageVBO::RAS_StorageVBO(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer):
m_texco_num(texco_num),
m_attrib_num(attrib_num),
m_texco(texco),
- m_attrib(attrib)
+ m_attrib(attrib),
+ m_attrib_layer(attrib_layer)
{
}
@@ -240,7 +239,7 @@ void RAS_StorageVBO::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi)
{
RAS_MeshSlot::iterator it;
VBO *vbo;
-
+
for (ms.begin(it); !ms.end(it); ms.next(it))
{
vbo = m_vbo_lookup[it.array];
@@ -254,6 +253,6 @@ void RAS_StorageVBO::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi)
vbo->UpdateData();
}
- vbo->Draw(*m_texco_num, m_texco, *m_attrib_num, m_attrib, multi);
+ vbo->Draw(*m_texco_num, m_texco, *m_attrib_num, m_attrib, m_attrib_layer, multi);
}
}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
index d8d8192e482..2fe0c32f399 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, bool multi);
+ void Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num, RAS_IRasterizer::TexCoGen* attrib, int *attrib_layer, bool multi);
void UpdateData();
void UpdateIndices();
@@ -66,7 +66,7 @@ class RAS_StorageVBO : public RAS_IStorage
{
public:
- RAS_StorageVBO(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib);
+ RAS_StorageVBO(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer);
virtual ~RAS_StorageVBO();
virtual bool Init();
@@ -85,6 +85,7 @@ protected:
RAS_IRasterizer::TexCoGen* m_texco;
RAS_IRasterizer::TexCoGen* m_attrib;
+ int* m_attrib_layer;
std::map<RAS_DisplayArray*, class VBO*> m_vbo_lookup;
diff --git a/source/gameengine/Rasterizer/SConscript b/source/gameengine/Rasterizer/SConscript
index 4ff79d9ce24..3e7dacad8ba 100644
--- a/source/gameengine/Rasterizer/SConscript
+++ b/source/gameengine/Rasterizer/SConscript
@@ -47,7 +47,10 @@ incs = [
defs = ['GLEW_STATIC']
if env['WITH_BF_PYTHON']:
- incs.append(env['BF_PYTHON_INC'])
+ if type(env['BF_PYTHON_INC']) == str:
+ incs.append(env['BF_PYTHON_INC'].split(' '))
+ else:
+ incs.append(env['BF_PYTHON_INC'])
defs.append('WITH_PYTHON')
if env['WITH_BF_CXX_GUARDEDALLOC']:
diff --git a/source/gameengine/SConscript b/source/gameengine/SConscript
index 3db973d9406..ae1bb756f8e 100644
--- a/source/gameengine/SConscript
+++ b/source/gameengine/SConscript
@@ -35,7 +35,6 @@ SConscript(['BlenderRoutines/SConscript',
'Ketsji/KXNetwork/SConscript',
'Network/SConscript',
'Network/LoopBackNetwork/SConscript',
- 'Physics/common/SConscript',
'Physics/Dummy/SConscript',
'Rasterizer/SConscript',
'Rasterizer/RAS_OpenGLRasterizer/SConscript',
diff --git a/source/tests/CMakeLists.txt b/source/tests/CMakeLists.txt
index dd84882bea3..1bda9e7ae9e 100644
--- a/source/tests/CMakeLists.txt
+++ b/source/tests/CMakeLists.txt
@@ -46,6 +46,10 @@ set(TEST_BLENDER_EXE ${TEST_BLENDER_EXE} --background -noaudio --factory-startup
# ------------------------------------------------------------------------------
# GENERAL PYTHON CORRECTNESS TESTS
+add_test(script_load_keymap ${TEST_BLENDER_EXE}
+ --python ${CMAKE_CURRENT_LIST_DIR}/bl_keymap_completeness.py
+)
+
add_test(script_load_addons ${TEST_BLENDER_EXE}
--python ${CMAKE_CURRENT_LIST_DIR}/bl_load_addons.py
)
diff --git a/source/tests/bl_keymap_completeness.py b/source/tests/bl_keymap_completeness.py
new file mode 100644
index 00000000000..00322907f69
--- /dev/null
+++ b/source/tests/bl_keymap_completeness.py
@@ -0,0 +1,84 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public 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>
+
+# simple script to test 'keyconfig_utils' contains correct values.
+
+
+from bpy_extras import keyconfig_utils
+
+
+def check_maps():
+ maps = {}
+
+ def fill_maps(ls):
+ for km_name, km_space_type, km_region_type, km_sub in ls:
+ maps[km_name] = (km_space_type, km_region_type)
+ fill_maps(km_sub)
+
+ fill_maps(keyconfig_utils.KM_HIERARCHY)
+
+ import bpy
+ keyconf = bpy.context.window_manager.keyconfigs.active
+ maps_bl = set(keyconf.keymaps.keys())
+ maps_py = set(maps.keys())
+
+ err = False
+ # Check keyconfig contains only maps that exist in blender
+ test = maps_py - maps_bl
+ if test:
+ print("Keymaps that are in 'keyconfig_utils' but not blender")
+ for km_id in sorted(test):
+ print("\t%s" % km_id)
+ err = True
+
+ test = maps_bl - maps_py
+ if test:
+ print("Keymaps that are in blender but not in 'keyconfig_utils'")
+ for km_id in sorted(test):
+ km = keyconf.keymaps[km_id]
+ print(" ('%s', '%s', '%s', [])," % (km_id, km.space_type, km.region_type))
+ err = True
+
+ # Check space/region's are OK
+ print("Comparing keymap space/region types...")
+ for km_id, km in keyconf.keymaps.items():
+ km_py = maps.get(km_id)
+ if km_py is not None:
+ km_space_type, km_region_type = km_py
+ if km_space_type != km.space_type or km_region_type != km.region_type:
+ print(" Error:")
+ print(" expected -- ('%s', '%s', '%s', [])," % (km_id, km.space_type, km.region_type))
+ print(" got -- ('%s', '%s', '%s', [])," % (km_id, km_space_type, km_region_type))
+ print("done!")
+
+ return err
+
+
+def main():
+ err = check_maps()
+
+ import bpy
+ if err and bpy.app.background:
+ # alert CTest we failed
+ import sys
+ sys.exit(1)
+
+if __name__ == "__main__":
+ main()